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

使用Ansible将本地文件Upsert至远程MongoDB遇问题求助

问题解决:Ansible通过stdin传JSON到mongoimport报错的处理

问题重现

我尝试用Ansible将本地JSON文件的记录Upsert到远程MongoDB集合,不想走"传文件→执行→删文件"的流程,于是写了两个任务:本地读取文件内容,远程通过stdin传给mongoimport执行Upsert。剧本代码如下:

- name: 读取users集合数据
  local_action:
    module: ansible.builtin.command
    cmd: cat files/mongo/users.js
  register: users_collection

- name: Upsert到MongoDB
  ansible.builtin.command:
    cmd: >-
      mongoimport
        --db mydb
        --collection users
        --jsonArray
        --mode upsert
        --upsertFields username
    stdin: "{{ users_collection.stdout }}"
  failed_when: result.stdout.find("0 document(s) failed to import.") != -1

但执行时mongoimport抛出奇怪错误:

Failed: error processing document #1: invalid character 'r' in literal Timestamp (expecting 'i')
0 document(s) imported successfully. 0 document(s) failed to import.

我的JSON里根本没有Timestamp类型,手动传文件到远程执行mongoimport完全正常,把剧本里的mongoimport换成cat验证输入内容也没问题,而且报错时显示"0个失败文档"也不符合逻辑。

原因分析与解决办法

1. 替换文件读取方式:用slurp代替cat

command: cat读取文件时可能引入隐藏的格式问题(比如换行符转换、编码异常),Ansible自带的slurp模块是专门用于读取文件内容的,能更可靠地处理文件编码和格式:

- name: 读取users集合数据
  local_action:
    module: ansible.builtin.slurp
    src: files/mongo/users.js
  register: users_collection

- name: Upsert到MongoDB
  ansible.builtin.command:
    cmd: >-
      mongoimport
        --db mydb
        --collection users
        --jsonArray
        --mode upsert
        --upsertFields username
    stdin: "{{ users_collection.content | b64decode }}"
  failed_when: "'Failed:' in result.stdout"

slurp返回的内容是Base64编码的,所以需要用b64decode过滤器解码后再传给stdin。

2. 换用shell模块执行mongoimport

command模块在处理stdin时可能存在字符转义或管道处理的问题,换成shell模块可以避免这类问题:

- name: Upsert到MongoDB
  ansible.builtin.shell: |
    mongoimport \
      --db mydb \
      --collection users \
      --jsonArray \
      --mode upsert \
      --upsertFields username
  stdin: "{{ users_collection.stdout }}"
  failed_when: "'Failed:' in result.stdout"

3. 处理换行符格式问题

如果你的JSON文件是Windows格式(CRLF换行),远程Linux主机上的mongoimport可能解析出错。可以在读取时直接转换为LF换行:

- name: 读取并转换换行符
  local_action:
    module: ansible.builtin.command
    cmd: cat files/mongo/users.js | tr -d '\r'
  register: users_collection

4. 修正failed_when的判断逻辑

你原来的failed_when逻辑写反了:当stdout包含"0 document(s) failed to import."时标记失败,但这句话实际表示没有失败文档,正确的判断应该是检查输出中是否存在"Failed:"字样,这样才能准确捕获错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 18:06:31