在MongoDB中存储null与根本不存储键

ia2d9nvy  于 2022-11-22  发布在  Go
关注(0)|答案(5)|浏览(291)

在我看来,当你创建一个Mongo文档,并有一个字段{key: value},有时是不会有一个值,你有两个选择:
1.写入{key: null},即在字段中写入空值
1.根本不要将密钥存储在该文档中
这两个选项都很容易查询,在一个选项中查询{key : null},在另一个选项中查询{key : {$exists : false}}
我实在想不出这两个选项之间有什么不同,它们在应用程序场景中会有什么影响(除了选项2的存储空间稍微少一点)。
有没有人能告诉我,有没有什么理由让人更喜欢这两种方法中的任何一种,为什么?

编辑

在问完这个问题后,我也想到了索引在这两种情况下的行为可能不同,即可以为选项2创建稀疏索引。

ujv3wf0j

ujv3wf0j1#

事实上,你还有第三种可能性:key: ""(空值)
而且你忘记了一个关于null值的特性。key: null上的查询将检索所有key为null**或key不存在的文档。
$exists:false上的查询将只检索字段键不存在的文档时。
要返回到您的确切问题,这取决于您的查询和数据表示的内容。如果您需要保留该字段,例如,用户设置了一个值,然后又取消设置它,您应该将该字段保留为null或空。如果不需要,您可以删除该字段。

agxfikkp

agxfikkp2#

请注意,由于MongoDB不使用字段名字典压缩,field:null会消耗磁盘空间和RAM,而根本不存储键则不会消耗资源。

ggazkfy8

ggazkfy83#

它实际上归结为:

  • 您的方案
  • 您的询问方式
  • 您的索引需要
  • 您的语言

我个人选择了存储空键。这使得它更容易集成到我的应用程序中。我使用PHP与活动记录和使用空值使我的生活更容易,因为我不必把压力的字段依赖于应用程序。我也不需要做任何复杂的代码来处理魔术设置不存在的变量。
我个人不会存储像""这样的空值,因为如果你不小心的话,你可能会有两个空值null"",然后你会有一个偶然的时间来查询特定的值。所以我个人更喜欢null作为空值。
至于空间和索引:这取决于有多少行可能没有这个列,但我怀疑你是否真的注意到索引大小的增加,因为一些额外的文档中有null。我的意思是存储的差异是很小的,特别是如果相应的键名也很小。这也适用于大型设置。
坦率地说,我不确定$existsnull之间的索引用法,但是null可能是一个更标准化的方法,通过它来查询存在性,因为请记住MongoDB是无模式的,这意味着您不需要在文档中拥有该字段,这又会产生两个空值:不存在和null。所以最好选择其中之一。
我选择null

s71maibg

s71maibg4#

您可能需要考虑的另一点是在使用OGM工具(如Hibernate OGM)时。
如果您使用的是Java,Hibernate OGM支持JPA标准。因此,如果您可以编写JPQL查询,那么,如果您希望切换到OGM工具支持的备用NoSQL数据存储库,理论上会很容易。
JPA没有为Mongo中的$exists定义一个等价的属性。所以如果你的集合中有可选的属性,那么你就不能为它写一个合适的JPQL。在这种情况下,如果属性的值存储为NULL,那么仍然可以写一个有效的JPQL查询,如下所示。

SELECT p FROM pppoe p where p.logout IS null;
6qqygrtg

6qqygrtg5#

我认为在磁盘空间方面的差异是可以忽略不计的。如果你需要在这个字段上创建索引,那么考虑部分索引。
{ partialFilterExpression: { key: { $exists: true } } }表示的指数可以比普通指数小得多。
还应注意,查询的外观不同,见如下值:

db.collection.insertMany([
  { _id: 1, a: 1 }, 
  { _id: 2, a: '' }, 
  { _id: 3, a: undefined }, 
  { _id: 4, a: null }, 
  { _id: 5 }
])
db.collection.aggregate([
   {
      $set: {
         type: { $type: "$a" },
         ifNull: { $ifNull: ["$a", true] },
         defined: { $ne: ["$a", undefined] },
         existing: { $ne: [{ $type: "$a" }, "missing"] }
      }
   }   
])
   
{ _id: 1, a: 1,         type: double,    ifNull: 1,    defined: true,  existing: true }
{ _id: 2, a: "",        type: string,    ifNull: "",   defined: true,  existing: true }
{ _id: 3, a: undefined, type: undefined, ifNull: true, defined: false, existing: true }
{ _id: 4, a: null,      type: null,      ifNull: true, defined: true,  existing: true }
{ _id: 5,               type: missing,   ifNull: true, defined: false, existing: false }

或者用db.collection.find()表示:

db.collection.find({ a: { $exists: false } })
  { _id: 5 }

db.collection.find({ a: { $exists: true} })
  { _id: 1, a: 1 }, 
  { _id: 2, a: '' }, 
  { _id: 3, a: undefined }, 
  { _id: 4, a: null }

db.collection.find({ a: null })
  { _id: 3, a: undefined }, 
  { _id: 4, a: null },
  { _id: 5 }

db.collection.find({ a: {$ne: null} })
  { _id: 1, a: 1 }, 
  { _id: 2, a: '' }, 

db.collection.find({ a: {$type: "null"} })
  { _id: 4, a: null }

相关问题