Mongojs attempting to push to array - node.js

I'm trying to keep a list of all the sites I'm working on right now, and I'm having issues using $push.
I've created a document with this:
accountData = {
'accountid': account_id,
sites: {
'001': 'example.com',
}
};
db.accounts.insert(accountData);
This works great, I get:
{ accountid: 'AC654164545', 'sites.001': { '$exists': true } }
And I would like to add to the sites object. This is what I'm trying:
db.accounts.update(
{'accountid': account_id},
{
$push:
{
sites:
{
'002': 'example2.com'
}
}
},
function(err,doc){
console.log(err);
}
);
The error that I get is:
err: 'The field \'sites\' must be an array but is of type Object in document
I don't want the document to be created with an array, as I know that if I did something like this when inserting:
sites: {
'002': 'example2.com',
'003': 'example3.com',
'004': 'example4.com',
}
It would work just fine.
How do I use $push, or any other command, to add to the "sites" object without it being an array?
It can't be an array because I'm using the following to search for existing sites.
search['sites.' + site_id] = { $exists : true };

Ok, I figured out what the problem was.
I wasn't thinking about the problem in the right context.
The error was correct in saying it needed to be an array, so I changed the "sites" object into an array like this when created (initial insert), so it's an array:
accountData = {
'accountid': account_id,
sites: [{'001': 'example.com'}]
};
Then, by using the exact same code above to $push, it worked properly.

Related

NodeJS How to make a get request with two parameteres in the query

i'm writing a get methode in node js and i have an error when i want get the data base it show me an error that the query return null despite the document exist
router.get('/getmodele',(req,res,next)=>{
let aa=req.query.imei;
console.log(aa);
Post.findOne( {imei: {
'imei.name':req.query.imei,'imei.modele':req.query.modele
},
test: {
$exists: false
}})
.
then((posts) => {
my request take at time two parameteres
i need some helps and thank you
Use dot notation when querying.
Post.findOne( {'imei.name':req.query.imei,'imei.modele':req.query.modele})
I think your query should be like this:
{
imei: {
name: req.query.imei,
modele: req.query.modele
}
}

Optional parameters on sequelize query

Good morning.
I'm quite new to NodeJS / sequelize world and I'm currently facing a problem while trying to display a dashboard on screen.
This dashboard has three filters: two dates (period), client name, and employee name. The user can select none, one, two, or all the filters and my database needs to work accordingly.
That being said, my problem is with Sequelize because I don't know how to treat this problem of parameters not being "always" there.
I've seen this question:
Sequelize optional where clause parameters?
but this answer doesn't work anymore. I also tried another way of building the where clause, but I failed on it as well (mainly due to sequelize operators).
The last thing I tried was to make a single query with all parameters included but try to find some value (or flag) that would make sequelize ignore the parameter, for the case when the parameter was no there*, but it looks like Sequelize doesn't have anything like that.
* I've read a question here that has an answer saying that {} would do the trick but I tried that as well but didn't work.
In summary: I need to make a query that can "change" over time, for example:
Foo.findAll({
where: {
id : 1,
}
});
Foo.findAll({
where: {
id {
[Op.in] : [1,2,3,4,5]
},
name: "palmeiira",
}
});
Do you know a way of doing it without the need of using a lot if / switch statements?
I'm currently using Sequelize v. 5.5.1.
Update
I tried doing as suggested by #Anatoly and created a function to build the parameters. It was something like that. (I tried a "smaller" version just to test)
async function test() {
const where = {};
where[Op.and] = [];
where[Op.eq].push({
id: {
[Op.in]: [1,2,3]
}
});
return where;
}
I setted the return value to a const:
const query = await test()
And tried console.log(query)
The result was: { [Symbol(and)]: [ { id: [Object] } ] }, which made me believe that the problem was parsing the Op part so i tried using 'Op.and' and 'Op.in' to avoid that and it solved this problem, but led to another on sequelize that said Invalid value
Do you have any idea where is my error ?
P.S.: #Anatoly very nice idea you gave me on original answer. Thank you very much.
If these three conditions should work together then you can use Op.and with an array of conditions:
const where = {}
if (datesFilter || clientNameFilter || employeenameFilter) {
where[Op.and] = []
if (datesFilter) {
where[Op.and].push({
dateField: {
[Op.between]: [datesFilter.start, datesFilter.finish]
}
})
}
if (clientNameFilter) {
where[Op.and].push({
name: {
[Op.iLike]: `%${clientNameFilter.value}%`
}
})
}
if (employeenameFilter) {
where[Op.and].push({
employeeName: {
[Op.iLike]: `%${employeenameFilter.value}%`
}
})
}
}
const dashboardItems = await DashboardItem.findAll({ where }, {
// some options here
})
If the conditions should work as alternatives then just replace Op.and with Op.or

I want to update sub document in array

I now use mongooses to pull and pull subdocuments to the array, and now I want to change the contents of the detail field of that subdocument with the _id of the subdocument.
{
subDocument: [{
_id: ObjectId('123'),
detail: 'I want update this part'
}]
}
I tried to use the $set method as shown below but it did not work as expected.
Model.findByIdAndUpdate(uid, { $Set: {subDocument: {_id: _id}}});
Looking at the for statement as shown below is likely to have a bad effect on performance. So I want to avoid this method.
const data = findById(uid);
for(...) {
if(data.subDocument[i]._id==_id) {
data.subDocument[i].detail = detail
}
}
Can you tell me some mongodb queries that I can implement?
And, Is it not better to use the 'for(;;)' statement shown above than to search using mongodb's query?
This should work:
Model.findOneAndUpdate({"subdocument._id": uid},
{
$set: {
"subdocument.$.detail ": "detail here"
}
},
).exec(function(err, doc) {
//code
});
To find subdocument by id, I am using something like this :
var subDocument = data.subDocument.id(subDocumentId);
if (subDocument) {
// Do some stuff
}
else {
// No subDocument found
}
Hope it helps.

Pushing new value to array in MongoDB document with NodeJS

I have a MongoDB collection with documents that look as follows:
{
"id": 51584,
"tracks": [],
"_id": {
"$oid": "ab5a7... some id ...cc81da0"
}
}
I want to push a single track into the array, so I try the following NodeJS code:
function addTrack(post,callback){
var partyId = post['partyId'], trackId = post['trackId'];
// I checked here that partyId and trackId are valid vars.
db.db_name.update({id: partyId}, { $push: { tracks: [trackId] } }, function(err, added) {
if( err || !added ) {
console.log("Track not added.");
callback(null,added);
}
else {
console.log("Track added to party with id: "+partyId);
callback(null,added);
}
});
}
This returns successfully with the callback that the track was added. However, when I inspect the database manually it is not updated and the array tracks is still empty.
I've tried a lot of different things for the tracks element to be pushed (ie. turning it into an array etc.) but no luck so far.
PS: Perhaps I should note that I'm using MongoLab to host the database.
Any help would be most welcome.
I found my problem, in the addTrack update({id: partyId},.. method partyId was not a string so it didn't find any docs to push to. Thanks to SudoGetBeer for leading me to the solution.
If your posted document is correct(get via find() i.e.):
tracks is a subdocument or embedded document ( http://docs.mongodb.org/manual/tutorial/query-documents/#embedded-documents )
The difference is simple: {} = Document, [] = Array
So if you want to use $push you need to update the tracks field to be an array
Here's how I'm doing it:
// This code occurs inside an async function called editArticle()
const addedTags = ['one', 'two', 'etc']
// ADD NEW TAGS IN MONGO DB
try {
const updateTags = addedTags.reduce((all, tag) => {
all.push(articles.updateOne({ slug: article.slug }, { $push: { tags: tag } }))
return all
}, [])
await Promise.all(updateTags)
} catch (e) {
log('error', 'addTags', e)
throw 'addTags'
}
addTags is the Array of tags, and we need to push them into Mongo DB one at a time so that the document we are pushing into looks like this after:
{
tags: ["existingTag1", "existingTag2", "one", "two", "etc"]
}
If you push an array like in the original question above, it would look like this:
{
tags: ["existingTag1", "existingTag2", ["one", "two", "etc"]]
}
So, tags[2] would be ["one", "two", "etc"], not what you want.
I have shown .reduce() which is an accumulator, which is a fancy, immutable way of doing this:
let updateTags = []
addedTags.forEach((tag) => {
updateTags.push(articles.updateOne({ slug: article.slug }, { $push: { tags: tag } }))
})
At this point, updateTags contains an array of functions, so calling Promise.all(updateTags) will run them all and detonate if any of them fail. Since we are using Mongo DB Native Driver, you will have to clean up if any errors occur, so you will probably want to track the pre-write state before calling Promise.all() (ie: What were the tags before?)
In the catch block, or catch block of the upper scope, you can "fire restore previous state" logic (rollback) and/or retry.
Something like:
// Upper scope
catch (e) {
if (e === 'addTags') rollback(previousState)
throw 'Problem occurred adding tags, please restart your computer.'
// This can now bubble up to your front-end client
}

MongoDB Upsert add to array

I'm trying to insert/update an array of strings in a mongodb document using some typescript code running in NodeJS.
The following code is typescript but I guess JS developers will get it w/o any problems:
export function addEvents(entityId: string,
events: string[] ,
callback: () => void) {
db.collection('events', function(error, eventCollection) {
if(error) {
console.error(error); return;
}
eventCollection.update({ _id: entityId }, { "$pushAll ":
{ events: events }},
function(error, result) {
if(error) {
console.error(error); return;
}
callback();
});
});
}
the document have the following structure:
{
_id : string
events : ["array","of","strings"]
}
I simply want to append an array strings at the end of the existing array for a specific _id.
I don't quite get if I should use update,save, $push ,$pushall etc.
Can someone explain?
If I understood correctly the problem is that pushAll does nothing or update returns error? Maybe copy-paste mistake in your example but I think you have typo here.
{ "$pushAll ": { events: events }}
It should be
{ $pushAll: { events: events }}
Your combination of update and $pushAll looks like the best choice for what you're doing here -- it's for appending an array to an existing array. $push is for adding an element to an array. save would involve getting the existing events array, appending to it, then saving the document.
The extra space in "$pushAll " needs to be removed. It may have quotes: "$pushAll".
Found the problem, I needed to pass "{ upsert = true }" as a third argument to the update function.
To achieve 'upsert' semantics in this case, you'd need to use $addToSet. If you have an array of values to add, you'd need to throw in the $each modifier. From mongo shell:
db.events.update(
{ _id: entityId },
{ $addToSet: { $each: events } }
)

Resources