Meteor/Mongo DB $gte operator not working on find(); - mongodb

I am trying to make a query so that I only return the 'productos' that are on the current 'categoria', they also need to have the 'stock.cantidad' field greater or equal than 1 and the 'stock.idCedis' equal to a specific value, and this is how I am trying to do it:
return Productos.find(
{
idCategoria: Router.current().params._id,
"stock.cantidad":{$gte: 1},
"stock.idCedis":idCedis
});
I checked and the "stock.idCedis":idCedis is working just fine displaying the 'productos' that have that specific 'idCedis', but what I am having problems with is the "stock.cantidad":{$gte: 1}, part because I don't know why Meteor or Mongo DB for that matter are just ignoring it.
The schema for the stock part of 'productos' that I am currently using is this:
stock: {
type: [Object]
},
"stock.$.cantidad": {
type: Number,
label: "Cantidad de Stock",
min: 0
},
"stock.$.idCedis": {
type: String,
label: "Centro de DistribuciĆ³n"
},
So I would like to know if I am doing something wrong or any other way I could make this work.

Since stock.$.cantitad is an array try $elemMatch:
return Productos.find(
{
idCategoria: Router.current().params._id,
"stock.cantidad":{$elemMatch {$gte: 1}},
"stock.idCedis":idCedis
});
The mongo docs indicate that you shouldn't need to do this when there's only a single query condition but given how Meteor interacts with mongo I'd give it a try.

Muchas gracias Michael Floyd, what I needed was that $elemMatch query operator, but for some reason your code did not worked form me, what worked was this:
Productos.find(
{
idCategoria: Router.current().params._id,
stock: { $elemMatch: { idCedis: idCedis, cantidad: { $gte: 0 } } }
});

Related

MongoDB updating the wrong subdocument in array

I've recently started using MongoDB using Mongoose (from NodeJS), but now I got stuck updating a subdocument in an array.
Let me show you...
I've set up my Restaurant in MongoDB like so:
_id: ObjectId("5edaaed8d8609c2c47fd6582")
name: "Some name"
tables: Array
0: Object
id: ObjectId("5ee277bab0df345e54614b60")
status: "AVAILABLE"
1: Object
id: ObjectId("5ee277bab0df345e54614b61")
status: "AVAILABLE"
As you can see a restaurant can have multiple tables, obviously.
Now I would like to update the status of a table for which I know the _id. I also know the _id of the restaurant that has the table.
But....I only want to update the status if we have the corresponding tableId and this table has the status 'AVAILABLE'.
My update statement:
const result = await Restaurant.updateOne(
{
_id: ObjectId("5edaaed8d8609c2c47fd6582"),
'tables._id': ObjectId("5ee277bab0df345e54614b61"),
'tables.status': 'AVAILABLE'
},
{ $set: { 'tables.$.status': 'CONFIRMED' } }
);
Guess what happens when I run the update-statement above?
It strangely updates the FIRST table (with the wrong table._id)!
However, when I remove the 'tables.status' filter from the query, it does update the right table:
const result = await Restaurant.updateOne(
{
_id: ObjectId("5edaaed8d8609c2c47fd6582"),
'tables._id': ObjectId("5ee277bab0df345e54614b61")
},
{ $set: { 'tables.$.status': 'CONFIRMED' } }
);
Problem here is that I need the status to be 'AVAILABLE', or else it should not update!
Can anybody point me in the wright direction with this?
according to the docs, the positional $ operator acts as a placeholder for the first element that matches the query document
so you are updating only the first array element in the document that matches your query
you should use the filtered positional operator $[identifier]
so your query will be something like that
const result = await Restaurant.updateOne(
{
_id: ObjectId("5edaaed8d8609c2c47fd6582"),
'tables._id': ObjectId("5ee277bab0df345e54614b61"),
'tables.status': 'AVAILABLE'
},
{
$set: { 'tables.$[table].status': 'CONFIRMED' } // update part
},
{
arrayFilters: [{ "table._id": ObjectId("5ee277bab0df345e54614b61"), 'table.status': 'AVAILABLE' }] // options part
}
);
by this way, you're updating the table element that has that tableId and status
hope it helps

mongodb need to populate a new field with an old fields value, without destroying other data

I have a situation where a model changed at some point in time and I am faced with (for argument sake) half my data liks like this
{
_id: OID,
things: [{
_id:OID,
arm: string,
body: string
}],
other: string
}
and the other half of my data look like this
{
_id: OID,
things: [{
_id:OID,
upper_appendage: string,
body: string
}],
other: string
}
I would like to 'correct' half of the data - so that I DON'T have to accommodate both names for 'arm' in my application code.
I have tried a couple different things:
The first errors
db.getCollection('x')
.find({things:{$exists:true}})
.forEach(function (record) {
record.things.arm = record.things.upper_appendage;
db.users.save(record);
});
and this - which destroys all the other data in
db.getCollection('x')
.find({things:{$exists:true}})
.forEach(function (record) {
record.things = {
upper_appendage.arm = record.things.upper_appendage
};
db.users.save(record);
});
Keeping in mind that there is other data I want to maintain...
How can I do this???
the $rename operator should have worked for this job but unfortunately it doesn't seem to support nested array fields (as of mongodb server 4.2). instead you'd need a forEach like the following:
db.items.find({
things: {
$elemMatch: {
arm: {
$exists: true
}
}
}
}).forEach(function(item) {
for (i = 0; i != item.things.length; ++i)
{
item.things[i].upper_appendage = item.things[i].arm;
delete item.things[i].arm; ;
}
db.items.update({
_id: item._id
}, item);
})
note: i've assumed you want to make all records have upper_appendageand get rid of 'arm' field. if it's the other way you want, just switch things around.

Updating a value that is dependent on a newly updated document key

My goal is to add a comment to my CommentFeed and while doing that I want to push that comment into my topComments field and also update the 'numOfComments' . I want to limit the topComments to only 3 comments (How would I even set that up?). And how do I take the previous value of numOfComments and add one to it?
CommentFeed.findOneAndUpdate(
{ _id: commentId },
{
$push: {
comments: {
text: req.body.text
},
$push: topComments:{text: req.body.text}, <--- Limit this somehow to only allow an array length of 3?
$set: numOfComments: ? , <---What kind of logic is used here?
}
},
{ new: true }
)
CommentFeed Schema
const CommentFeedSchema = new Schema({
topComments:[{text:{type:String}}],
numOfComments:{type:Number},
comments: [
text: { type: String, required: true }
]});
For the first issue (limiting the topComments array size) you can use the $slice operator. This has already been answered in other questions. But you might consider computing topComments from comments using the$slice operator in the projection argument:
CommentFeed.find( {}, { comments: { $slice: -3 } } )
For the second issue (updating a document using existing fields from that document), it is not something you can do in a simple findOneAndUpdate call. This was also discussed in other questions.
But you might consider computing numOfComments instead of updating it every time. You can do that with the $size operator of the aggregation framework:
CommentFeed.aggregate({$project: { numOfComments: { $size:"$comments" }}})

Trouble updating a Simple Schema sub document

I'm trying to update a sub document on an existing collection. I'm getting a MongoDB error message.
"MongoError: The positional operator did not find the match needed from the query. Unexpanded update: articleWords.$ [409]"
From my Articles Simple Schema
"articleWords.$": {
type: Object
},
"articleWords.$.wordId": {
type: String,
label: 'Word ID'
},
"articleWords.$.word": {
type: String,
label: 'Word'
},
Update Function
function updateArticle(_id,wordArr) {
_.each(wordArr,function(elem) {
var ret = Articles.update(
{'_id': _id},
{ $set: { 'articleWords.$': { 'wordId': elem.wordId, 'word': elem.word } }
});
});
return true;
}
As you can see I am passing an array of objects. Is there a better way to do this than _.each ?
CLARIFICATION
Thank you to #corvid for the answer. I think I didn't make my question clear enough. There does exist an article record, but there is no data added to the articleWords attribute. Essentially we are updating a record but insert into the articleWords array.
A second attempt, is also not working
_.each(wordArr,function(elem) {
var ret = Articles.update(
{'_id': _id},
{ $set: { 'articleWords.$.wordId': elem.wordId, 'articleWords.$.word': elem.word } }
);
});
Yes, you need your selector to match something within the subdocument. For example,
Articles.update({
'_id': <someid>,
'words.wordId': <somewordid>
}, {
$set: {
'words.$.word': elem.word,
'words.$.wordId': elem.wordId
}
});
If the array doesn't exist yet then you're going about this in the hardest way possible. You can just set the entire array at one go:
var ret = Articles.update(
{'_id': _id},
{ $set: { articleWords: wordArr }}
);
I can see that wordArr already has the id and string. This will work as long as it doesn't have more content. If it does then you can just make a second version with the parts you want to keep.

Issue in Updating an Array Object in mongoDb

I am trying to update an Array object based on a condition. Following is my scenario :-
I want to update status from current to archive.
I have tried many things for hours but still no luck. Like this :-
db.user.update({
'injury._id': ObjectId("5374cb4d1e0386c02800006a"),
'injury.injurydata.locationaddressinjury': {
$elemMatch: {
'status': 'current'
}
}
}, {
$set: {
'injury.injurydata.locationaddressinjury.status': 'archive'
}
})
The picture made it hard to read the structure of your data. But I guess the update you are looking for would be something like this:
db.user.update({
'injury._id': ObjectId("5374cb4d1e0386c02800006a"),
'injury.injurydata.locationaddressinjury': {
$elemMatch: {
'status': 'current'
}
}
}, {
$set: {
'injury.injurydata.locationaddressinjury.$.status': 'archive'
}
});
The $ would refer to the element you found. While if you are looking for a way to update all element at one time. I'm afraid $elemMatch would just match the first element that satisfies your condition.