spring-data-mongodb與mongo shell的對應關系


除了特殊注釋外,本文的測試結果均基於 spring-data-mongodb:1.10.6.RELEASE(spring-boot-starter:1.5.6.RELEASE),MongoDB 3.0.6


   上一章我們了解了mongo shell中aggregate復雜的互相調用關系。那么,spring-data-mongodb中aggregate又是如何與mongo交互的?是將語句拼接成我們熟悉的函數(db._collection_.find/update...)還是命令(db.runCommand)?讓我們來看底層的代碼到底是怎么樣的。

  以下為 mongoTemplate.aggregate 方法的底層實現

    private void sendMessage(final CommandMessage message, final InternalConnection connection) {
        ByteBufferBsonOutput bsonOutput = new ByteBufferBsonOutput(connection);
        try {
            int documentPosition = message.encodeWithMetadata(bsonOutput).getFirstDocumentPosition();
            sendStartedEvent(connection, bsonOutput, message, documentPosition);

            connection.sendMessage(bsonOutput.getByteBuffers(), message.getId());
        } finally {
            bsonOutput.close();
        }
    }

   在往下就是字節流了,就直接看着里的數據吧,message數據為:

   test是連接的數據庫名稱,test.$cmd相當於db.$cmd,有過第二章的基礎,這里應該明白,這個方法是走runCommand的$cmd集合的。那么相應的 mongoTemplate.getDb().command 以及 mongoTemplate.getCollection("$cmd").findOne 都可以拼接出來。

  因為這些方法需要的拼接很復雜的bson,所以這里我們引用另外一個操作符$eval。熟悉js的朋友應該都知道,eval是可以將字符串轉換成方法執行的,這里我們就使用原生的aggregate語句字符串,讓mongo shell去處理字符串。

  如下是五種使用$eval的方法

        //注意:命令的key:value部分,value必須被[]或者{}或者''包裹。js的字符串支持單引號和雙引號兩種,這里使用單引號是為了避免在java中使用大量的 \
     String command = "db.user.aggregate([{$group:{_id:'$name',count:{$sum:'$age'}}}])"; BasicDBObject bson = new BasicDBObject(); bson.put("$eval",command); Object object1 = mongoTemplate.getDb().doEval(command); Object object2 = mongoTemplate.getDb().command(bson); Object object3 = mongoTemplate.getCollection("$cmd").findOne(bson); ScriptOperations operations = mongoTemplate.scriptOps(); ExecutableMongoScript script = new ExecutableMongoScript(command); Object object4 = operations.execute(script); /** * call是調用system.js集合中方法的方法,傳入參數是sysytem.js表中數據的主鍵值, * 可在mongo shell中天插入或者使用如下代碼插入。 * 插入一次后可直接使用 */ // String command = "function(){return db.user.aggregate([{$group:{_id:'$name',count:{$sum:'$age'}}}])}"; // NamedMongoScript namedMongoScript = new NamedMongoScript("user2",script); // operations.register(namedMongoScript); Object object5 = operations.call("user2");

   那么,find函數是否也如mongo shell 中,讓我們繼續來看看底層代碼

private <T> List<T> executeFindMultiInternal(CollectionCallback<DBCursor> collectionCallback, CursorPreparer preparer,
            DbObjectCallback<T> objectCallback, String collectionName) {
        try {
            DBCursor cursor = null;
            try {
                cursor = collectionCallback.doInCollection(getAndPrepareCollection(getDb(), collectionName));
                if (preparer != null) {
                    cursor = preparer.prepare(cursor);
                }
                List<T> result = new ArrayList<T>();
                while (cursor.hasNext()) {
                    DBObject object = cursor.next();
                    result.add(objectCallback.doWith(object));
                }
                return result;
            } finally {
                if (cursor != null) {
                    cursor.close();
                }
            }
        } catch (RuntimeException e) {
            throw potentiallyConvertRuntimeException(e, exceptionTranslator);
        }
    }

  我們可以看到find也如mongo shell中一樣,走的是游標的路線。

  通過上面的一系列代碼的研究,我們學會了使用多種方法實現原生的aggregate,並且弄明白了aggregate在mongo shell 或者spring-data-mongodb中都存在多層的、暴露的調用方法,而find類型的請求是直接調用到了游標,這樣設計的目的是什么?有興趣的讀者可以繼續看看第四章 mongo中的游標與數據一致性的取舍

 


 目錄

  一:spring-data-mongodb 使用原生aggregate語句

  二:mongo的runCommand與集合操作函數的關系

  三:spring-data-mongodb與mongo shell的對應關系

  四:mongo中的游標與數據一致性的取舍


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM