确保mongodb中嵌入式文档中的唯一索引

时间:2014-04-04 03:32:19

标签: mongodb

有没有办法让列表中的子文档在mongodb中有一个唯一的字段?

文件结构:

{
        "_id" : "2013-08-13",
        "hours" : [
                {
                        "hour" : "23",
                        "file" : [
                                {
                                        "date_added" : ISODate("2014-04-03T18:54:36.400Z"),
                                        "name" : "1376434800_file_output_2014-03-10-09-27_44.csv"
                                },
                                {
                                        "date_added" : ISODate("2014-04-03T18:54:36.410Z"),
                                        "name" : "1376434800_file_output_2014-03-10-09-27_44.csv"
                                },
                                {
                                        "date_added" : ISODate("2014-04-03T18:54:36.402Z"),
                                        "name" : "1376434800_file_output_2014-03-10-09-27_44.csv"
                                },
                                {
                                        "date_added" : ISODate("2014-04-03T18:54:36.671Z"),
                                        "name" : "1376434800_file_output_2014-03-10-09-27_44.csv"
                                }
                        ]
                }
        ]
}

我想确保文档的hours.hour值在插入时具有唯一的项目。问题是小时是一个列表。你能用这种方式确保索引吗?

1 个答案:

答案 0 :(得分:1)

索引不是确保嵌入式数组唯一性的工具,而是跨文档使用它们以确保某些字段不会在那里重复。

只要您可以确定要添加的内容与任何其他值没有任何区别,那么您可以使用$addToSet运算符进行更新:

db.collection.update(
    { "_id": "2013-08-13", "hour": 23 },
    { "$addToSet": { 
        "hours.$.file": {
            "date_added" : ISODate("2014-04-03T18:54:36.671Z"),
            "name" : "1376434800_file_output_2014-03-10-09-27_44.csv"
        }
    }}
)

因此,文档将,因为已存在与目标数组中的精确值匹配的元素。如果内容不同(这意味着任何部分内容,则会添加新项目。

对于其他任何事情,您需要通过加载文档并检查数组元素来手动维护。假设一个具有完全相同时间戳的不同“文件名”。

架构问题

现在回答问题我想指出架构设计存在的问题。

  1. 日期作为字符串是“可怕的”。你可能认为你需要它们,但你不需要它们。有关详细信息,请参阅聚合框架date operators

  2. 您有嵌套数组,通常应避免使用。常见问题显示在positional $运算符的文档中。这表示你只能在位置上获得一个匹配,而总是“顶级”数组。因此,除了如上所示添加内容之外的更新将很困难。

  3. 更好的架构模式是简单地执行此操作:

        {
            "date_added" : ISODate("2014-04-03T18:54:36.400Z"),
            "name" : "1376434800_file_output_2014-03-10-09-27_44.csv"
        },
        {
            "date_added" : ISODate("2014-04-03T18:54:36.410Z"),
            "name" : "1376434800_file_output_2014-03-10-09-27_44.csv"
        },
        {
            "date_added" : ISODate("2014-04-03T18:54:36.402Z"),
            "name" : "1376434800_file_output_2014-03-10-09-27_44.csv"
        },
        {
            "date_added" : ISODate("2014-04-03T18:54:36.671Z"),
            "name" : "1376434800_file_output_2014-03-10-09-27_44.csv"
        }
    

    如果它在自己的集合中,那么您始终可以使用索引来确保唯一性。聚合框架可以根据需要细分日期部分和小时。

    您必须将其作为另一个文档的一部分,然后尝试至少避免嵌套数组。这是可以接受的,但不像分隔条目那样灵活:

    {
        "_id" : "2013-08-13",
        "hours" : {
            "23": [
                {
                    "date_added" : ISODate("2014-04-03T18:54:36.400Z"),
                    "name" : "1376434800_file_output_2014-03-10-09-27_44.csv"
                },
                {
                    "date_added" : ISODate("2014-04-03T18:54:36.410Z"),
                    "name" : "1376434800_file_output_2014-03-10-09-27_44.csv"
                },
                {
                    "date_added" : ISODate("2014-04-03T18:54:36.402Z"),
                    "name" : "1376434800_file_output_2014-03-10-09-27_44.csv"
                },
                {
                    "date_added" : ISODate("2014-04-03T18:54:36.671Z"),
                    "name" : "1376434800_file_output_2014-03-10-09-27_44.csv"
                }
            ]
        }
    }
    

    这取决于您的预期用途,最后一次不允许您在一天内的几个小时内进行任何类型的聚合比较。不是以任何简单的方式。前者很容易做到这一点,你仍然可以轻松地按天和小时分解选择。

    然后,再次,如果您只是附加信息,那么应该找到您现有的架构。但请注意可能的问题和替代方案。