Mongodb- Query to check if a field in the json array exists or not - mongodb

I have a JSON in MongoDB and I am trying to check if at least one of the items in the JSON doesn't contain a specific field.
{
"_id" : 12345,
"orderItems" : [
{
"itemId" : 45678,
"isAvailable" : true,
"isEligible" " false
},
{
"itemId" : 87653,
"isAvailable" : true
}
]
}
So in the above JSON, since the 2nd one under order items doesn't contain iseligible field, I need to get this _id.
I tried the below query so far, which didnt work:
db.getCollection('orders').find({"orderItems.iseligible":{$exists:false})

You can use $elemMatch to evaluate the presence of the nested key. Once that's accomplished, project out the _id value.
db.orders.find({
orderItems: {
$elemMatch: {
"isEligible": {
$exists: false
}
}
}
},
{
_id: 1
})
Here is a Mongo playground with the finished code, and a similar SO answer.

Related

mongodb - how to insert a new key/value on each array's element if not present (with mongo query)

I would like to update each elements (object) in an array of a company.
Here my actual data :
{
_id: ObjectId("60d31024860ce0400b586111")
contracts:
[
{
name: 1.pdf
url: "https://someurl"
createdAt: 2021-06-23T10:42:44.594+00:00
}
{
name: 2.pdf
url: "https://someurl"
}
{
name: 3.pdf
url: "https://someurl"
}
]
}
I would like to add a defined date on each object (in contracts) that has no "updatedAt" key.
Here what I tried :
db.companies.update({ _id: ObjectId("60d31024860ce0400b586111"),"contracts.createdAt": { $exists: false } },{ $set: { "contracts.$.createdAt": "test" } })
but I got this error :
"The positional operator did not find the match needed from the query."
I have also tried this and it works, but I don't wanna query by file name. I just wanna add "createdAt" on each elements found that has no "createdAt"
db.companies.update({ "contracts.name": "2.pdf" },{ $set: { "contracts.$.createdAt": "atest" } })
I think you need to use the filtered position operator:
$ - updates the first matched array element
$[] - updates all the matched elements with a specific condition
The specific condition is mentioned in the arrayFilters key.
db.students.update(
{ },
{ $set: { "contracts.$[element].createdAt" : "atest"} },
{ multi: true,
arrayFilters: [ { "element.createdAt": { $exists: false } } ]
}
)
multi - true is to apply the operation on all the matching documents.
Also notice, how the first query parameter is empty, which means the query runs for all documents. I used it based on the second query you wrote but you can also add in an ObjectID query there.

How do I update a field in a sub-document array with a field from the document in MongoDB?

I have a large amount of data (~160M items) where a date value wasn't populated on the sub-document array fields, but was populated on the parent document. I'm very new to MongoDB and having trouble figuring out how to $set the field to match. Here's a sample of the data:
{
"_id": "5f11d4c48663f32e940696ed",
"Widgets":[{
"WidgetId":663,
"Name":"Super Widget 2.0",
"Created":null,
"LastUpdated":null
}],
"Status":3,
"LastUpdated":null,
"Created": "2018-11-09T18:22:16.000Z"
}
}
My knowledge of MongoDB is pretty limited but here's the basic aggregation I have created for part of the pipeline and where I'm struggling:
db.sample.aggregate(
[
{
"$match" : {
"Donors.$.Created" : {
"$exists" : true
}
}
},
{
"$match" : {
"Widgets.$.Created" : null
}
},
{
"$set" : {
"Widgets.$.Created" : "Created" // <- This is where I can't figure out how to define the reference to the parent "Created" field
}
}
]
);
The desired output would be:
{
"_id": "5f11d4c48663f32e940696ed",
"Widgets":[{
"WidgetId":663,
"Name":"Super Widget 2.0",
"Created":"2018-11-09T18:22:16.000Z",
"LastUpdated":null
}],
"Status":3,
"LastUpdated":null,
"Created": "2018-11-09T18:22:16.000Z"
}
}
Thanks for any assitance
Are you attempting to add the Created field to sub documents on query/aggregation? Or are you attempting to update/save the Created field on the subdocuments?
The $ is an update operator, to be used with updateMany or updateOne. Not aggregate.
https://docs.mongodb.com/manual/reference/operator/query-array/
https://docs.mongodb.com/manual/reference/operator/update-array/
If you just want to add the parents Created field to all subdocuments on query/aggregation this is all you have to do: https://mongoplayground.net/p/yHDHULCSTIz
db.collection.aggregate([
{
"$addFields": {
"Widgets.Created": "$Created"
}
}
])
If your attempting to save the parents Created field to all subdocuments:
db.sample.updateMany({"Widgets.Created" : null}, [{$set: {"Widgets.Created" : "$Created"}}])
Note: This matches any doc that has a subdocument with a null Created field and updates all the subdocuments.

Query by two params with $and in mongoose?

I have a user model like this:
user : {
myArmy : {
mySoldiers : [
{
positioned : false,
soldierInfo : {
_id : s99212
}
},
{
positioned : true,
soldierInfo : {
_id : s99112
}
}
]
}
},
user : {
myArmy : {
mySoldiers : [
{
positioned : true,
soldierInfo : {
_id : s99212
}
},
{
positioned : false,
soldierInfo : {
_id : s99112
}
}
]
}
}
...
I have a query that i want to do to return the user(s) who have soldier id s99212 positioned (true): (could be thousands of those, and i need to read and retrieve them all)
This is my faulty query with mongoose:
var soldierId = s99212;
stream = User.find({
$and: [
{'myArmy.mySoldier.positioned': {$ne: null}},
{'myArmy.mySoldier.soldierInfo._id': soldierId}
]
}).lean(true).stream();
Nothing is returned by this query, should there be another way to do this $and stuff?
How exactly am i suppose to use $elemMatch if at all, should it be instead of the find? (If it worth to mention, i want to return the complete user object, not just parts of it...)
Tried this, crashed my app:
stream = User.find({
'$elemMatch': [
{'myArmy.mySoldiers.pos': {$ne: null}},
{'myArmy.mySoldiers.soldierInfo._id': soldierId}
]
}).lean(true).stream();
I know i have a small syntax problem, where is it?
Very simple and well documented. The $elemMatch operator acts as a "query in itself", where it applies "it's conditions" to members of the array specified:
var query = User.find({
"myArmy.mySoldiers": {
"$elemMatch": {
"positioned": { "$ne": null },
"soldierInfo._id": soldierId
}
}
});
Therefore for a document to "match" then the conditions specfied under $elemMatch must be present and valid for the "same" array element. Array on "left", arguments on "right".
Other "dot notation" forms only ever test that the values match "some element" in the array, and not necessarily the same one.

How to get all matching subdocuments in mongoose?

In my mongodb (using Mongoose), I have story collection which has comments sub collection and I want to query the subdocument by client id, as
Story.find({ 'comments.client': id }, { title: 1, 'comments.$': 1 }, function (err, stories) {
...
})
})
The query works except that it only returns the first matched subdocument, but I want it to return all matching subdocuments. Did I miss an option?
EDIT:
On Blakes Seven's tip, I tried the answers from Retrieve only the queried element in an object array in MongoDB collection, but I couldn't make it work.
First tried this:
Story.find({'comments.client': id}, { title: 1, comments: {$elemMatch: { client: id } } }, function (err, stories) {
})
It also returns the first match only.
Then, I tried the accepted answer there:
Story.aggregate({$match: {'comments.client': id} }, {$unwind: '$comments'}, {$match : {'comments.client': id} }, function (err, stories) {
})
but this returns nothing. What is wrong here?
UPDATE:
My data structure looks like this:
{
"_id" : ObjectId("55e2185288fee5a433ceabf5"),
"title" : "test",
"comments" : [
{
"_id" : ObjectId("55e2184e88fee5a433ceaaf5"),
"client" : ObjectId("55e218446033de4e7db3f2a4"),
"time" : ISODate("2015-08-29T20:16:00.000Z")
}
]
}

Mongodb: Trying to find all documents with specific subdocument field, why is my query not working?

Here is an example of a document from the collection I am querying
meteor:PRIMARY> db.research.findOne({_id: 'Z2zzA7dx6unkzKiSn'})
{
"_id" : "Z2zzA7dx6unkzKiSn",
"_userId" : "NtE3ANq2b2PbWSEqu",
"collaborators" : [
{
"userId" : "aTPzFad8DdFXxRrX4"
}
],
"name" : "new one",
"pending" : {
"collaborators" : [ ]
}
}
I want to find all documents within this collection with either _userId: 'aTPzFad8DdFXxRrX4' or from the collaborators array, userId: 'aTPzFad8DdFXxRrX4'
So I want to look though the collection and check if the _userId field is 'aTPzFad8DdFXxRrX4'. If not then check the collaborators array on the document and check if there is an object with userId: 'aTPzFad8DdFXxRrX4'.
Here is the query I am trying to use:
db.research.find({$or: [{_userId: 'aTPzFad8DdFXxRrX4'}, {collaborators: {$in: [{userId: 'aTPzFad8DdFXxRrX4'}]}}] })
It does not find the document and gives me a syntax error. What is my issue here? Thanks
The $in operator is basically a simplified version of $or but you really only have one argument here so you should not even need it. Use dot notation instead:
db.research.find({
'$or': [
{ '_userId': 'aTPzFad8DdFXxRrX4'},
{ 'collaborators.userId': 'aTPzFad8DdFXxRrX4'}
]
})
If you need more than one value then use $in:
db.research.find({
'$or': [
{ '_userId': 'aTPzFad8DdFXxRrX4'},
{ 'collaborators.userId': {
'$in': ['aTPzFad8DdFXxRrX4','aTPzFad8DdFXxRrX5']
}}
]
})