如何根据特定 id 向 mLab 数组插入新项目

How to insert a new item to mLab array according to a specific id

我的数据库使用 mLab。我有一个列表集合,其中每个列表都有一个带有 _id、userId 和项目数组的对象。

现在我想向特定列表的数组中添加一个新项目。

连接到 Mongo 的函数有新的项目对象和列表 ID。

如何找到正确的列表并将新项目添加到项目数组?

每个列表的 JSON 如下所示:

{
    "_id": {
        "$oid": "5ded5eb7e7179a3015b0672f"
    },
    "userID": "1234",
    "items": [
        {
            "_id": "abc12345",
            "name": "abc",
        },
        {
            "_id": "abc12346",
            "name": "def",
        }
    ]
}

连接到 Mongo 的函数如下所示:

function addItem({item, listId}) {
    return MongoService.connect()
    .then(db => {
        const collection = db.collection('lists');
        //need to do something here
    })
}

连接到 Mongo:(工作正常,我连接并加载列表)

function connectToMongo() {
    if (dbConn) return Promise.resolve(dbConn);
    const MongoClient = require('mongodb').MongoClient;
    const url = 'mongodb:// ***my user and password ***';
    return MongoClient.connect(url)
        .then(client => {
            console.log('Connected to MongoDB');
            client.on('close', ()=>{
                console.log('MongoDB Diconnected!');
                dbConn = null;
            })
            dbConn = client.db()
            return dbConn;
        })
}
module.exports = {
    connect : connectToMongo
}

我通常会使用 Ramda and/or partial.lenses 这样的库来解决这样的问题。这些库中的任何一个都将简化处理通常来自 mongodb.

的复杂 and/or 嵌套数据的工作

partial.lenses 可能是处理复杂的嵌套数据结构的更强大的选项,但我不确定如何将它嵌入这里的代码片段中,而 Ramda 在这方面并不懈怠,所以这是一个 Ramda 示例:

const lists = [
  {
    _id: { $oid: '1234' },
    items: []
  },
  {
    _id: { $oid: '2345' },
    items: []
  },
  {
    _id: { $oid: '3456' },
    items: []
  }
]

function addItem({item, listId}) {
  const ix = lists.findIndex(
    ({ _id }) => _id.$oid === listId
  )
  return R.over(R.lensPath([ix, 'items']), R.append(item), lists)
}

console.log(
  addItem({ item: 'hi', listId: '1234' })
)

console.log(
  addItem({ item: 'hi', listId: '3456' })
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>

为了后代,这里是 link 到 working solution based on partial.lenses

这是一个不依赖库的解决方案。老实说,它有点乱,如果我不能使用库,我会花一些时间编写一些可重用的实用函数,这些函数将成为我编写的任何实际生产解决方案的一部分。我在以前的项目中做过这个,但代码不是开源的,我认为这个练习不在这个答案的范围内。

我希望这个工作示例能让您朝着正确的方向前进:

const _lists = [
  {
    _id: { $oid: '1234' },
    items: []
  },
  {
    _id: { $oid: '2345' },
    items: []
  },
  {
    _id: { $oid: '3456' },
    items: []
  }
]

const getListById = (listId, lists) =>
  lists.find(({ _id }) => _id.$oid === listId)

const setListById = (listId, newList, lists) =>
  lists.reduce(
    (acc, list, i) =>
      list._id.$oid === listId
        ? (acc.push(newList), acc)
        : (acc.push(list), acc),
    []
  )

function addItem({item, listId}) {
  const oList = getListById(listId, _lists)
  const newList = {
    ...oList,
    items: [...oList.items, item]
  }
  return setListById(listId, newList, _lists)
}

console.log(
  addItem({ item: 'hi', listId: '1234' })
)

console.log(
  addItem({ item: 'hi', listId: '3456' })
)

另外,一个警告:所有这些示例都假定始终有一个列表对象与所提供的 listId 相匹配。如果这不是一个安全的假设,您需要添加一些逻辑来处理失败情况(即 findIndex 将 return -1 而不是实际的数组索引和 find将 returned undefined 而不是列表对象)。

我看到您正在使用 MongoDB 节点本机驱动程序。有关如何使用驱动程序 here.

更新 MongoDB 文档的文档

为了向 list.items 数组添加一个项目,addItem 函数应该如下所示:

function addItem({ item, listId }) {
  return MongoService.connect()
    .then(db => {
      const collection = db.collection('lists');
      // The update query below would return a promise
      return collection.updateOne({
        { _id: new ObjectID(listId) }
      }, { '$push': { items: item } })
    })
    .then(result => { // Anything you want to do with the result })
}