为mongoDB非规范化JSON

时间:2014-01-15 04:21:50

标签: json mongodb

我认为这就是我要找的那个词。我正在尝试将父信息输入每张卡片。我认为这就是我需要做的事情,但如果你有任何其他想法,请加入。

{
  "LEA": {
    "name": "Limited Edition Alpha",
    "code": "LEA",
    "releaseDate": "1993-08-05",
    "border": "black",
    "type": "core",
    "cards": [
      {"name": "Air Elemental"},
      {"name": "Earth Elemental"},
      {"name": "Fire Elemental"},
      {"name": "Water Elemental"}
    ]
  },
  "LEB": {
    "name": "Limited Edition Beta",
    "code": "LEB",
    "releaseDate": "1993-10-01",
    "border": "black",
    "type": "core",
    "cards": [
      {"name": "Armageddon"},
      {"name": "Fireball"},
      {"name": "Swords to Plowshares"},
      {"name": "Wrath of God"}
    ]
  }
}

显然,这是数据的一小部分。 LEALEB是卡片组,每组中都有一堆卡片。我正在考虑将这种非正规化为卡片,并将设置信息添加到每张卡片中。像这样......

{
  {
    "name": "Air Elemental",
    "set": {
      "name": "Limited Edition Alpha",
      "code": "LEA",
      "releaseDate": "1993-08-05",
      "border": "black",
      "type": "core"
    }
  },
  {
    "name": "Earth Elemental",
    "set": {
      "name": "Limited Edition Alpha",
      "code": "LEA",
      "releaseDate": "1993-08-05",
      "border": "black",
      "type": "core"
    }
  },
  {
    "name": "Armageddon",
    "set": {
      "name": "Limited Edition Beta",
      "code": "LEB",
      "releaseDate": "1993-10-01",
      "border": "black",
      "type": "core"
    }
  },
  {
    "name": "Fireball",
    "set": {
      "name": "Limited Edition Beta",
      "code": "LEB",
      "releaseDate": "1993-10-01",
      "border": "black",
      "type": "core"
    }
  }
}

我的想法是否正确,首先是?我想要一个巨大的cards集合,并将设置的信息展平到每张卡片中吗?在SQL中,我会为这些集做一个表,并且这些卡会belong_to一组。我试图围绕'文档思考'。

其次,如果我的想法是正确的,关于如何实现这种非规范化的任何想法?

1 个答案:

答案 0 :(得分:1)

这里你去=)。

好的,这是我要去的地方。由于我们已经说卡片永远不会改变(因为它们基于物理MTG卡),所以创建一个包含所有卡片的集合,这将用于以后轻松填充用户的卡片。您可以使用卡片名称或某种卡片ID(如存储在卡片上的物理卡片ID)进行搜索。

对于用户的卡片对象数组,您不应只存储卡片的_id字段,因为这会强制您加入。由于卡片永远不会改变,因此完全非规范化它们并将它们推入该卡片阵列中,因此到目前为止,用户对象类似于:

{
  name: "Tom Hanks",
  skill_level: 0,
  decks: [
    [
      { 
        card_name: "Balance", 
        card_description: "LONG_BLOCK_OF_DESCRIP_TEXT", 
        card_creator: "Sugargirl14", 
        type: "Normal",
        _id: $SOME_MONGO_ID_HERE,
        ... rest of card data...
      }, {
         ...card 2 complete data...
      }
    ],
    [
      { ...another deck here... }
    ]
  ]
}

好的,回到设置信息,我也会假设设置信息是一个常数(基于你的SO帖子,我看不出它会如何改变)。因此,如果该集合信息始终与卡片相关,我会将其归一化并包含它,将我们的卡片对象更改为:

      { 
        card_name: "Balance", 
        card_description: "LONG_BLOCK_OF_DESCRIP_TEXT", 
        card_creator: "Sugargirl14", 
        type: "Normal",
        _id: $SOME_MONGO_ID_HERE
        set: {
          "name": "Limited Edition Alpha",
          "code": "LEA",
          "releaseDate": "1993-08-05",
          "border": "black",
          "type": "core",
          "_id": $SOME_MONGO_ID_HERE
        },
        ... rest of card data...
      }

我认为将其他卡存储在给定卡的非规范化对象中是不相关的,如果是,则添加它们。如果你注意到,你的SO示例中给出的密钥将被删除,因为它似乎总是==“代码”字段。

好的,现在要正确回答你关于是否应该将卡片嵌入卡片的问题,反之亦然。首先,两个集合都是相关的。因此,即使我们将集合嵌入到卡片中,您也会希望将这些集合放入集合中,以便以后可以将其取出并插入新卡片中。

嵌入的内容实际上取决于业务逻辑,数据的使用方式以及更频繁的数据。您是否经常展示套装并从中拉出卡片(例如用户搜索)?您可以在每个集合的cards数组中嵌入所有卡数据或任何相关数据。但是使用上述数据模型,每张卡都将其设置ID存储在其设置对象中。我假设卡片只属于一套,所以要获得一套卡片,你可以在卡片集合中查询你想要的set.id == the Mongo ID集合。由于业务逻辑,现在需要最少的更新(希望根本没有),并且您的查询仍然很快(并且您获得完整的卡对象)。老实说,我会做那个后者,并保持我的设置清洁卡。因此,卡拥有其所属的集合,而非拥有卡。这是一种更为SQL的方式,认为它实际上可以在Mongo中正常工作(你永远不会加入)。

所以我们的最终数据模型类似于:

Collection 1,Set:

//data model
{
    "name": "Limited Edition Alpha",
    "code": "LEA",
    "releaseDate": "1993-08-05",
    "border": "black",
    "type": "core",
    "_id": $SOME_MONGO_ID_HERE
}

收集2,卡片:

//data model
{ 
  _id: $SOME_MONGO_ID_HERE
  card_name: "Balance", 
  card_description: "LONG_BLOCK_OF_DESCRIP_TEXT", 
  card_creator: "Sugargirl14", 
  type: "Normal",
  set: {
    "name": "Limited Edition Alpha",
    "code": "LEA",
    "releaseDate": "1993-08-05",
    "border": "black",
    "type": "core",
    "_id": $SOME_MONGO_ID_HERE
     ... rest of card data...
  },
}

收藏3,用户:

{
  _id: $SOME_MONGO_ID_HERE,
  name: "Tom Hanks",
  skill_level: 0,
  decks: [
    [
      { 
        card_name: "Balance", 
        card_description: "LONG_BLOCK_OF_DESCRIP_TEXT", 
        card_creator: "Sugargirl14", 
        type: "Normal",
        _id: $SOME_MONGO_ID_HERE,
        set: {
          "name": "Limited Edition Alpha",
          "code": "LEA",
          "releaseDate": "1993-08-05",
          "border": "black",
          "type": "core",
          "_id": $SOME_MONGO_ID_HERE
        },
      }, {
         ...card 2 complete data...
      }
    ],
    [
      { ...another deck here... }
    ]
  ]
}

这显然假设每张卡的设定数据与用户相关。现在你的数据被非规范化,集合和卡很少需要更新(根据业务逻辑),所以你永远不需要级联更新或删除。操纵用户很容易。当您从用户的牌组中移除一张牌时,您可以在相关的牌组数据上从Mongo(我认为这就是所谓的)执行$pull,其中包含项目的_id字段== Mongo ID你要删除的卡。所有其他更新都更容易。

回想起来,您可能希望像这样制作用户的套牌:

decks: {
  "SOME_ID_HERE": [
    { ...card 1... },
    { ...card 2... }
  ] 
}

这使得识别甲板变得更容易,并且可以使您的拉动变得更容易(您将在前端获得更多数据,并且拉取查询将更加精确)。它可以是一个数字,随机字符串,任何真正的东西,因为它被传递回前端。或者只是使用他们的Mongo ID,当看到牌组时,用户将拥有它的Mongo ID。然后,当他们从中拉出一张卡片,或者添加一张卡片时,你就有了一个直接的标识符,可以轻松抓住所需的卡片。

显然所有带有文本的值如:$ MONGO_ID_HERE应该是MongoId()对象。

哇,那是激烈的,6800个字符。希望它对你有意义,如果任何措辞令人困惑或我的任何JSON对象的格式被搞砸了,我都会道歉(只是让我知道如果任何散文令人困惑,我会改写)。这是否有意义/解决您的问题?