通过PHP插入中使用的存储函数运行多次


Stored function used in insert trough PHP runs multiple times

我试图理解使用mongodb 2.4.3 win32 PHP的奇怪行为。我尝试让服务器端生成序列id。

当使用存储函数作为参数之一插入文档时,似乎每次插入都要调用该存储函数数次。

假设我有一个这样初始化的计数器:

db.counters.insert( { _id: "uqid", seq: NumberLong(0) } );

我有一个名为getUqid的存储函数,定义为

db.system.js.save( 
    { _id: "getUqid", 
      value: function () { 
                  var ret = db.counters.findAndModify(
                  { query: { _id: "uqid" }, 
                    update: { $inc: { seq: NumberLong(1) } }, 
                    new: true 
                  } );
                  return ret.seq; 
                  } 
             }  );

当我像这样做三次插入时:

$conn->test->ads->insert(['qid' => new MongoCode('getUqid()') , 'name' => "Sarah C."]);

我得到了这样的东西:

db.ads.find()
{ "_id" : ObjectId("51a34f8bf0774cac03000000"), "qid" : 17, "name" : "Sarah C." }
{ "_id" : ObjectId("51a34f8bf0774cac03000001"), "qid" : 20, "name" : "Michel D." }
{ "_id" : ObjectId("51a34f8bf0774cac03000002"), "qid" : 23, "name" : "Robert U." }

知道为什么qid被步进3吗?这应该意味着我收到了三个对存储函数的调用,对吗?

提前感谢你的帮助,Regards.

PS:次要问题:NumberLong仍然需要确保我们在mongodb内部存储有64位无符号整数吗?有没有在shell中交叉检查的命令?

与PHP-841交叉引用这个问题。从PHP方面来看,您实际上是在qid字段中存储BSON代码值。您可以在从数据库获取结果或使用mongodump命令执行数据库导出时验证这一点。

问题是JS shell错误地评估显示时的代码类型,这就是findAndModify执行的地方。这个修复应该包含在后续的服务器版本中。

同时,Sammaye建议从PHP调用findAndModify是实现这类功能的最佳选择。巧合的是,这也是在Doctrine MongoDB ODM中所做的(参见:IncrementGenerator)。它确实需要额外的往返服务器,但这是必要的,因为MongoDB没有在写操作期间执行JS回调的设施。

如果最小化到MongoDB的往返是最重要的,您可以通过使用MongoDB::execute()通过PHP执行服务器端JS插入文档,并做一些类似返回生成的ID(s)作为命令响应的事情。当然,这通常是不可取的,JS的求值有它自己的警告。