索引并插入一个 mongo 子文档

Posted

技术标签:

【中文标题】索引并插入一个 mongo 子文档【英文标题】:Index and upsert a mongo subdocument 【发布时间】:2014-10-24 02:02:51 【问题描述】:

我正在开发 mongo,我想做以下事情:

when a set of (lat, lon, uid) comes in:

1. the collection has lat as unique index, also for each lat the lon index is unique
2. if (lat, lon) pair exists in this collection, update uid in the sub-document
3. if (lat) exists in this document , insert (lon, uid) in the lons sub-document
4. if (lat) document doesn't exist, create lat document and do 2

[
    "lat" : 1,  (doc is unique by lat)
    "lons" : [ 
        
            "lon" : 2,   (the subdocument is unique by lon)
            "uid" : 3
        ,
        
            "lon" : 3,
            "uid" : 3
        
    ]
,

    "lat" : 2,
    "lons" : [ 
        
            "lon" : 2,
            "uid" : 4
        
    ]
]

我尝试做以下事情,但显然它没有像我想象的那样工作。

db.zones.update('lat': 90, $push: lons: 'uid' : 0, 'lon': -18,  upsert: true )
db.zones.ensureIndex('lat': -1, 'lons.lon':1, unique: true)

我检查了这篇帖子 Can mongo upsert array data? 和其他一些帖子,但不知何故,它们都没有工作。我不知道这是我的问题还是 mongo 的问题。谢谢!

【问题讨论】:

【参考方案1】:

我建议您重新考虑您的架构:

upsert 适用于文档级别,这与架构的结构不太匹配。如果在 lons 数组中未找到匹配项,您希望推送到现有文档而不是创建新文档。

包含无限增长的数组的文档可能会导致频繁的文档移动和性能问题(请参阅:Why shouldn't I embed large arrays in my documents?)

您的架构不适合地理空间索引(这需要经度/纬度对作为数组或嵌入文档)。我猜这对您的用例并不重要,因为您要确保正常的唯一索引,但这可能值得考虑。

更好的架构(假设您不打算使用地理空间查询)是:


    lon: -74.0059,
    lat: 40.7127,
    uid: 3

有了这个修改后的架构,您的更新要求就更直接了。

    集合具有 lat 作为唯一索引,对于每个 lat,lon 索引也是唯一的

您仍然希望确保唯一索引:

      db.zones.ensureIndex('lat': 1, 'lon':1, unique: true)

2。如果此集合中存在 (lat, lon) 对,则更新子文档中的 uid

3。如果 (lat) 存在于该文档中,则在 lons 子文档中插入 (lon, uid)

4。如果 (lat) 文档不存在,则创建 lat 文档并执行 2

所有这些逻辑现在都可以由upsert 处理:

db.zones.update(

    // query criteria
     lat: 40.7127, lon: -74.0060 ,

    // update
     $set: 
        uid: 3
    ,

    // options
    
        upsert: true
    
)

如果您想在更新现有文档时保留uid,也可以使用$setOnInsert 运算符(而不是$set):

db.zones.update(

    // query criteria
     lat: 40.7127, lon: -74.0060 ,

    // update
     $setOnInsert: 
        uid: 3
    ,

    // options
    
        upsert: true
    
)

【讨论】:

我之前也在考虑这个问题。问题是我将在 lon 中有大约 10k 点,在 lat 中有 10k 点,这意味着我将以这种方式创建 100m 文档。这还是一个好的设计吗? 绝对!阅读我在large embedded arrays 上引用的博文。在这两种情况下,对于唯一的纬度/经度对,您拥有相同数量的索引条目,因此将索引视为大致相同的大小。但是,如果您在每个 lat 文档中嵌入了 10k lon 值的数组,则由于文档超出了磁盘空间(每次文档移动,该文档的所有索引条目也必须是更新),如果您只需要检索文档中的一个点,服务器必须将整个文档加载到 RAM 中。 我明白了。对于以这种方式创建的 NxN 文档,查询时间是 O(1) 还是 O(N^2) ?您还可以为我推荐一些更多的查询资源,更新 mongo 的费用吗?大O的东西?非常感谢!! 我打算对 NxN 表执行的操作是,我会在其中插入一些 uid,在完成 N^2 次插入后,除了查询(很长一段时间。 )。在这种情况下,您仍然认为 NxN 文档是一个好的设计吗?

以上是关于索引并插入一个 mongo 子文档的主要内容,如果未能解决你的问题,请参考以下文章

更新/插入子文档时的 mongodb 性能

Mongo突然忽略大集合中的索引

如何将子文档插入 mongo 集合?

如何将子文档插入 mongo 集合?

mongo索引

MongoDB索引