You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从MongoDB获取数据并执行聚合查询时应用崩溃求助

问题描述

尝试从MongoDB获取数据并执行聚合查询,点击按钮后应用崩溃,错误日志及代码如下,求问题原因及解决方案。

错误日志

2023-12-17 17:10:57.338  1082-1715  OneSearchS...stProvider com...le.android.apps.nexuslauncher  E  Failed to fetch suggestions from AppSearch, fallback to AGA
java.util.concurrent.CompletionException: java.util.NoSuchElementException: No value present
at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:308)
at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:323)
at java.util.concurrent.CompletableFuture$UniAccept.tryFire(CompletableFuture.java:684)
at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:486)
at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2138)
at com.google.android.apps.nexuslauncher.allapps.H0.onResult(Unknown Source:59)
at android.app.appsearch.SearchSessionUtil$1.lambda$onResult$0(SearchSessionUtil.java:129)
atandroid.app.appsearch.SearchSessionUtil$1.$r8$lambda$_nlk9WiPjSfaAsqKYmp0aPvSRC0(SearchSessionUtil.java:1)
atandroid.app.appsearch.SearchSessionUtil$1$$ExternalSyntheticLambda0.run(R8$$SyntheticClass:13) 
at android.os.Handler.handleCallback(Handler.java:958)
atandroid.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:144)
at com.google.android.apps.nexuslauncher.allapps.H0.onResult(Unknown Source:16)
at android.app.appsearch.SearchSessionUtil$1.lambda$onResult$0(SearchSessionUtil.java:129) 
at android.app.appsearch.SearchSessionUtil$1.$r8$lambda$_nlk9WiPjSfaAsqKYmp0aPvSRC0(SearchSessionUtil.java:1) 
at android.app.appsearch.SearchSessionUtil$1$$ExternalSyntheticLambda0.run(R8$$SyntheticClass:13) 
at android.os.Handler.handleCallback(Handler.java:958) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loopOnce(Looper.java:205) 
at android.os.Looper.loop(Looper.java:294) 
at android.os.HandlerThread.run(HandlerThread.java:67) 

相关代码

获取MongoClient代码

@SuppressLint("AuthLeak")
fun getMongoClient(): MongoClient {
    return MongoClients.create("My String goes here -> taken from mongodb")
}

从MongoDB获取数据代码

fun fetchDataFromMongoDB(collection: MongoCollection<Document>): List<Document> {
    // Define your aggregation pipeline stages here
    val pipeline = listOf(
        Aggregates.match(Filters.eq("age", "20")),
        // Add more pipeline stages as needed
    )

    // Execute the aggregation pipeline
    val result = collection.aggregate(pipeline)


    // Convert the result to a list of documents
    val documents = mutableListOf<Document>()

    try {
        // Code that might be causing the exception
        result.forEach { document ->
            documents.add(document)
            println("Pinged your deployment. You successfully connected to MongoDB!")

        }

    } catch (e: Exception) {
        e.printStackTrace()
    }


    return documents
} 

主界面代码

@Composable
fun MainMongoData() {
    var fetchedData by remember { mutableStateOf("") }

    Column {
        // Display your fetched data in a TextField
        TextField(
            value = fetchedData,
            onValueChange = { /* No-op for read-only TextField */ },
            label = { Text("Fetched Data") },
            readOnly = true,
            modifier = Modifier.fillMaxWidth()
        )

        // Button to trigger search
        Button(onClick = {
            val client = getMongoClient()
            val database = client.getDatabase("people")
            val collection = database.getCollection("person")

            val documents = fetchDataFromMongoDB(collection)

            // Concatenate document JSON strings and update the TextField
            fetchedData = documents.joinToString("\n") { it.toJson() }

            client.close()
        }) {
            Text("Search")
        }
    }
}

问题原因及解决方案

1. 错误日志的误导性

日志中显示的崩溃来自系统启动器的AppSearch模块,和你的MongoDB代码无关。实际崩溃是因为代码中存在未正确处理的异常,未在日志中完整输出。

2. 核心问题:主线程执行网络操作

MongoDB请求在Compose按钮的点击回调中直接执行,属于主线程上的远程数据库操作,Android会抛出NetworkOnMainThreadException导致崩溃,而现有代码的try-catch未有效拦截该异常。

3. 聚合查询的潜在问题

  • Filters.eq("age", "20")如果数据库中age是数字类型,字符串匹配会查不到数据,但不会直接崩溃;
  • 聚合查询返回的游标未手动关闭,可能导致资源泄漏。

解决方案

(1)切换到后台线程执行数据库操作

使用协程将数据库操作放到IO线程,更新UI时切回主线程:

@Composable
fun MainMongoData() {
    var fetchedData by remember { mutableStateOf("") }
    val scope = rememberCoroutineScope()

    Column {
        TextField(
            value = fetchedData,
            onValueChange = {},
            label = { Text("Fetched Data") },
            readOnly = true,
            modifier = Modifier.fillMaxWidth()
        )

        Button(onClick = {
            scope.launch(Dispatchers.IO) {
                var client: MongoClient? = null
                try {
                    client = getMongoClient()
                    val database = client.getDatabase("people")
                    val collection = database.getCollection("person")
                    val documents = fetchDataFromMongoDB(collection)

                    withContext(Dispatchers.Main) {
                        fetchedData = documents.joinToString("\n") { it.toJson() }
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                    withContext(Dispatchers.Main) {
                        fetchedData = "请求失败: ${e.message}"
                    }
                } finally {
                    client?.close()
                }
            }
        }) {
            Text("Search")
        }
    }
}

(2)完善数据获取逻辑与异常处理

确保游标安全遍历并手动关闭,同时修正age的匹配类型:

fun fetchDataFromMongoDB(collection: MongoCollection<Document>): List<Document> {
    val pipeline = listOf(
        Aggregates.match(Filters.eq("age", 20)) // 若age为数字类型,用20而非"20"
    )

    val documents = mutableListOf<Document>()
    var cursor: MongoCursor<Document>? = null
    try {
        cursor = collection.aggregate(pipeline).iterator()
        while (cursor.hasNext()) {
            documents.add(cursor.next())
        }
    } catch (e: Exception) {
        e.printStackTrace()
    } finally {
        cursor?.close()
    }
    return documents
}

(3)配置必要权限与连接信息

在AndroidManifest.xml中添加网络权限:

<uses-permission android:name="android.permission.INTERNET" />

同时确认MongoDB连接字符串包含正确的用户名、密码、集群地址等信息。


内容的提问来源于stack exchange,提问作者Josef M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 16:06:05