I'm having dataset in which json consists of array having multiple json in it.
The objects in the array have 4 keys, out of which 1 is missing in some of them.
I want to get the documents where all the objects in an array are missing the key.
e.g, From these following documents:
{"test":1,desc:[{"price":1,"abc":"def"},{"price":2,"ac":"def"}]}
{"test":1,desc:[{"price":1,"abc":"def"},{"ac":"def"}]}
{"test":1,desc:[{"abc":"def"},{"ac":"def"}]}
I want to match only the last document.
Thanks in advance..
You can just use $exists:
db.collection.find(
{
"desc.price": {$exists: false}
}
)
And if you want for other fields as well:
db.collection.find(
{
$or: [
{
"desc.price": {$exists: false}
},
{
"desc.abc": {$exists: false}
},
{
"desc.ac": {$exists: false}
}
]
}
)
One thing to note is that an empty array, i.e desc = [] will always be matched by this query. if you want to ensure there's atleast one object use this query:
db.collection.find(
{
$and: [
{
"desc.price": {$exists: false}
},
{
"desc.0": {$exists: true}
}
]
}
)
Achieved that, just made a script where i used an array to store the price thing and then used .every method for price to be undefined , it returned me the desired result which i want.
Related
I am trying to get the positional index of an array element (to push more elements at $position). I'm specifically targeting a single document (say, id=x)
Simplified document:
{
id:"x",
samples:[{"timestamp":123},{"timestamp":234},{"timestamp":345}}
}
Aggregation pipeline:
collection.aggregate([{"$match": {"id": "x"}},
{"$project": {"matchedIndex": {"$indexOfArray": ["$samples.timestamp", 234]}}}])
This works to return matchedIndex=1 .
Now I would like to find the index of 'samples' where timestamp is greater than say 235, which should return '2'
I have tried combinations of:
collection.aggregate([{"$match": {"UUID": "5fd41e35-5e49-O977-t091-6f228bc65e37"}},
{"$project": {"matchedIndex":
{"$indexOfArray": ["$samples.timestamp",
{"$gt": ["$$timestamp", 235]}]}}}])
I understand this wont work, I'm just not sure how to go about it.
The purpose is to insert many elements between timestamps. Maybe there is a better way entirely to do this. Thanks
Instead of using "$samples.timestamp" as first argument you can use $map there to transform it into an array of true and false values depending on your condition, try:
{
"$project": {
"matchedIndex": {
"$indexOfArray": [
{ $map: { input: "$samples.timestamp", in: { $gte: [ "$$this", 235 ] } } },
true
]
}
}
}
Mongo Playground
I've a document like this:
{
"_id" : ObjectId("xxx"),
"users" : [
{
"_id" : ObjectId("xxx")
},
{
"_id" : ObjectId("yyy")
}
]
}
users is an array, which can contain two or more than two objects.
If I've to request strictly two objects via a mongo query, how can I do it?
.find({
"users._id" : { $in: [ObjectId("xxx"), ObjectId("yyy")] }
})
This above query will fetch all the docs that've either've xxx user or yyy user in them. How can I form a query where if the both xxx and yyy are only there, then only that doc is to be fetched.
Let me know if you need more info to understand the problem. And huge thanks in advance for the help.
You should use $all to force the need for all ids in the array to match but it is not enough on it's own as you'll still match documents with those two users + other users.
To combat that you will also have to make sure the users array is of size 2, you can do it like so:
db.collection.find({
$and: [
{
"users._id": {
$all: [
ObjectId("609a80e3c548140e5859d6de"),
ObjectId("60136b272c1e946545da6204")
]
}
},
{
"users.2": {
$exists: false
}
}
]
})
Mongo Playground
I have a range of documents
{
_id: ObjectId("5e388da4df54cb8efb47e61b"),
userId:'test_user'
productId:'product_6_id'
recommendations:{
_id:123
rankedList:[
0:{id:ObjectId('product_5_id'),Name:'Product_5'},
1:{id:ObjectId('product_6_id'),Name:'Product_6'},
2:{id:ObjectId('product_3_id'),Name:'Product_3'}],
Date:'2020-02-25T05:03:55.439+00:00'
}
},
{
_id: ObjectId("5e388da4df54cb8efb47e62b"),
userId:'test_user1'
productId:'product_3_id'
recommendations:{
_id:123
rankedList:[
0:{id:ObjectId('product_1_id'),Name:'Product_1'},
1:{id:ObjectId('product_5_id'),Name:'Product_5'},
2:{id:ObjectId('product_3_id'),Name:'Product_3'}],
Date:'2020-02-25T05:03:55.439+00:00'
}
}
and I need to find each time the position of productId within the Array of objects rankedList.
Thus here the answer would be positionIndex=1 for first doc and positionIndex=2 for second document.
I am quite confused with $indexOfArray and how I should use it here with aggregate.
Yes, you need $indexOfArray. The tricky part is that recommendations.rankedList is an array of objects however MongoDB allows you to use following expression:
$recommendations.rankedList.id
which evaluates to a list of strings, ['product_5_id', 'product_6_id', 'product_3_id'] in this case so your code can look like this:
db.collection.aggregate([
{
$project: {
index: {
$indexOfArray: [ "$recommendations.rankedList.id", "$productId" ]
}
}
}
])
Mongo Playground
I have flat objects stored in mongo and one of them have the field00048 attribute but my query is still returning entries without field00048. Can someone tell me what's wrong with my mongo query? I have attached a picture of the database below to show the structure.
db.QA_Book_01.find({
field00048: { $exists: true }},
{
$and:[
{ 'entryTypeId': 'Entry_Type_01' },
{ 'field00048': { $ne : 'Closed' }}]
}).count();
Out of 3 records, there is only one with the field 'field00048'. When I change the entryTypeId to Entry_Type_02, it still retrieves the record with the field 'field00048'. Not sure what's going on here.
By default, there is an and operation in find query of MongoDB so the proper syntax for applying an and operation in find query is mentioned below.
db.users.find( { $and: [ {field00048: { $exists: true }},
{ 'entryTypeId': 'Entry_Type_01' },
{ 'field00048': { $ne : 'Closed' }} ] } )
Example document:
{
"_id" : "5fTTdZhhLkFXpKvPY",
"name" : "example",
"usersActivities" : [
{
"userId" : "kHaM8hL3E3As7zkc5",
"startDate" : ISODate("2015-06-01T00:00:00.000Z"),
"endDate" : ISODate("2015-06-01T00:00:00.000Z")
}
]
}
I'm new in mongoDB and I read other questions about updating nested array and I can't do it properly. What I want to do is to change startDate and endDate for user with given userId. My problem is that it always pushes new object to array instead of changing object with given userId.
Activity.update(
_id: activityId, usersActivities: {
$elemMatch: {
userId: Meteor.userId()
}
}},
{
$push: {
'usersActivities.$.startDate': start,
'usersActivities.$.endDate': end
}
}
);
I will be really glad of help.
So the first thing to say here is the $elemMatch is not required in your case as you only want to match on a single array property. You use that operator when you need "two or more" properties from the same array element to match your conditions. Otherwise you just use "dot notation" as a standard.
The second case here is with $push, where that particular operator means to "add" elements to the array. In your case you just want to "update" so the correct operator here is $set:
Activity.update(
{ "_id": activityId, "usersActivities.userId": Meteor.userId() },
{
"$set": {
'usersActivities.$.startDate': start,
'usersActivities.$.endDate': end
}
}
)
So the positional $ operator here is what matches the "found index" from the array element and allows the $set operator to "change" the elements matched at that "position".
"What if Meteor.userId() does not exist, how to insert the whole of object with userID, startDate and endDate? – justdiehard Jun 14 at 20:20"
If you try to put new, you should take a look at Meteor Accounts package, there are methods like
Accounts.createUser(YOU_USER_SCHEME)