Reputation: 113
I use mLab for my database. I have a collection of lists where each list has an object with _id, userId and an array of items.
Now I want to add a new item to the array of a specific list.
The function that connects to Mongo has the new item object and the list id.
How do I find the correct list and add the new item to items array?
the JSON of each list looks like this:
{
"_id": {
"$oid": "5ded5eb7e7179a3015b0672f"
},
"userID": "1234",
"items": [
{
"_id": "abc12345",
"name": "abc",
},
{
"_id": "abc12346",
"name": "def",
}
]
}
and the function that connects to Mongo looks like this:
function addItem({item, listId}) {
return MongoService.connect()
.then(db => {
const collection = db.collection('lists');
//need to do something here
})
}
connect to Mongo : (which works fine, I do connect and load the lists)
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
}
Upvotes: 1
Views: 116
Reputation: 2573
I see you are using the MongoDB node native driver. Documentation exists on how to update a MongoDB document with the driver here.
In order to add an item to list.items
array, this is what the addItem
function should look like:
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 })
}
Upvotes: 1
Reputation: 2766
I'd generally reach for a library like Ramda and/or partial.lenses to solve a problem like this. Either of those libraries will simplify working with complicated and/or nested data that often comes from mongodb.
partial.lenses is probably the more powerful option for dealing with complicated, nested data structures, but I'm not sure how to embed it in a snippet here, and Ramda is no slouch in this area, so here's a Ramda example:
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>
For posterity, here's a link to a working solution based on partial.lenses.
Here's a solution that has no library dependencies. Honestly, it's a bit messy, and if I were not able to use a library, I would spend some time writing a handful of reusable utility functions that would become a part of any actual production solution I wrote. I've done this on previous projects, but the code isn't open source, and I think that exercise is outside the scope of this answer.
I hope this working example will get you moving in the right direction:
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' })
)
Also, a caveat: All of these examples assume there will always be a list object matching the provided listId
. If that's not a safe assumption, you'll need to add some logic to handle the failure case (i.e. findIndex
will return -1
rather than an actual array index and find
will returned undefined
rather than a list object).
Upvotes: 0