A user may send or receive a message, and should be able to archive his/her message regardless.
This .find should therefore return any docs where userA is in to.username or from.username, with view.archive:true. From there, the second $or should filter the results from the first $or to only include the matching docs where the message's value.1:true, value.2:true, or value.3:true
Right now, however, there is SyntaxError: Unexpected token ] for the closing ] on the first $or
Models.Messages.find(
{
"$or" : [
{
"to": {
"$elemMatch": {
"username": 'userA',
"view.archive": true,
"view.bin": true
}
}
},
{
"from" : {
"$elemMatch" : {
"username" : 'userA',
"view.archive": true,
"view.bin": true
}
}
}
],
"$or": [
{ 'value.1': true },
{ 'value.2': true },
{ 'value.3': true },
{ 'value.4': false }
]
}
).sort([['updated','descending']]).exec(function (err, messages) {
Both of these messages should be found for userA:
{
"_id" : ObjectId("53e83867f316ea7f22fd3b2b"),
"updated" : ISODate("2014-08-11T03:29:06.000Z"),
"message" : "message1",
"value" : [
"1" : true,
"2" : false,
"3" : false,
"4" : false
]
"to" : [
{
"user" : ObjectId("53e835bd76e0d04318d8cc4e"),
"username" : "userA",
"_id" : ObjectId("53e83867f316ea7f22fd3b2c"),
"view" : {
"inbox" : false,
"outbox" : false,
"archive" : true,
"bin" : false
}
}
],
"from" : [
{
"user" : ObjectId("53e8360276e0d04318d8cc55"),
"username" : "userB",
"_id" : ObjectId("53e83867f316ea7f22fd3b2d"),
"view" : {
"inbox" : false,
"outbox" : true,
"archive" : false,
"bin" : false
}
}
],
"__v" : 5
}
{
"_id" : ObjectId("53e83867f316ea7f22fd3b2b"),
"updated" : ISODate("2014-08-11T03:29:06.000Z"),
"message" : "message2",
"value" : [
"1" : false,
"2" : true,
"3" : false,
"4" : false
]
"to" : [
{
"user" : ObjectId("53e8360276e0d04318d8cc55"),
"username" : "userB",
"_id" : ObjectId("53e83867f316ea7f22fd3b2c"),
"view" : {
"inbox" : true,
"outbox" : false,
"archive" : false,
"bin" : false
}
}
],
"from" : [
{
"user" : ObjectId("53e835bd76e0d04318d8cc4e"),
"username" : "userA",
"_id" : ObjectId("53e83867f316ea7f22fd3b2d"),
"view" : {
"inbox" : false,
"outbox" : true,
"archive" : true,
"bin" : false
}
}
],
"__v" : 5
}
Thanks to #JohnnyHK for his answer to this question as it also applies here.
Was under the impression that $and was implied with .find in MongoDB, but when combining $or filters it appears to be necessary, as also pointed out by #soulcheck.
Models.Messages.find(
{
$and: [{
"$or" : [
{
"to": {
"$elemMatch": {
"username": 'userA',
"view.archive": true,
"view.bin": false
}
}
},
{
"from" : {
"$elemMatch" : {
"username" : 'userA',
"view.archive": true,
"view.bin": false
}
}
}
]}, {
"$or": [
{ 'value.1': true },
{ 'value.2': true },
{ 'value.3': true },
{ 'value.4': false }
]
}
]
}
).sort([['updated','descending']]).exec(function (err, messages) {
Related
actually i want to update specific object in my documents array which has viewProfile : true but it's gonna update all elements in array
here is my query:
const user = await User.updateMany(
{
_id: req.userData.id,
"notifications.viewProfile" : true
},
{
$set: {
"notifications.$[].read": false
}
}
);
consider this document
/* 1 */
{
"_id" : ObjectId("5e4ae76bd4e24418a020b665"),
"username" : "test",
"notifications" : [
{
"createdAt" : ISODate("2020-02-18T19:22:24.809Z"),
"_id" : ObjectId("5e4c397075265a36203dab5a"),
"message" : "testone is now following you.",
"viewProfile" : false,
"read" : false
},
{
"createdAt" : ISODate("2020-02-18T19:22:29.200Z"),
"_id" : ObjectId("5e4c397575265a36203dab5d"),
"message" : "testone is now following you.",
"viewProfile" : true,
"read" : false
}
],
}
Use filtered positional operator $[<identifier>] . Reference https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/
const user = await User.update(
{
_id: req.userData.id
},
{ $set: { "notifications.$[element].read": false } },
{
multi: true,
arrayFilters: [ { "element.viewProfile": true } ]
}
)
How to update Single object in array of objects by rules query is that object must by in document that has translation_key == as input that i read and object must have same language (id) if not i must create new object . ( mongodb, mongoose)
Language are required and uniueq in translations
{
"_id" : ObjectId("5bfd5324725fb12bc4863cd8"),
"deleted" : false,
"deleted_at" : null,
"noAuth" : false,
"hidden" : false,
"translation_key" : "Standard",
"translation_type" : "text",
"translation" : [
{
"system" : {
"android" : false,
"ios" : false,
"web" : false,
"api" : false
},
"language" : ObjectId("5bf52e06edb9902e2113d8b3"),
"text":'',
"active" : false,
"prepared_string" : false,
"_id" : ObjectId("5bfd910c2998d929644abd90"),
"params" : []
},
{
"system" : {
"android" : false,
"ios" : false,
"web" : true,
"api" : false
},
"active" : false,
"prepared_string" : false,
"_id" : ObjectId("5bfdb5d22998d929644ac2af"),
"language" : ObjectId("5bf52e06edb9902e6471d8c1"),
"text" : "Standard",
"app_version" : "2.0",
"params" : []
}
],
"create_date" : ISODate("2018-11-27T14:22:28.635Z"),
"update_date" : ISODate("2018-11-27T14:22:28.635Z"),
"__v" : 3
}
Model.findOneAndUpdate(
{
_id: "document_id",
"translation.language": "languageId",
},
{
$set: {
"translation.$.text: "text",
"translation.$.active": "status",
"translation.$.system.android" : true
},
{ new: true, upsert: true, }
)
.lean();
My collection named user have 6 fields. Profile field is document. It have only array named Packages. Packages is collection of documents, which contains all packages current user have.
My database is like:
{
"_id" : "AayujR3SLT5MtmTKf",
"createdAt" : ISODate("2015-09-18T07:19:05.069Z"),
"services" : {
"password" : {
"bcrypt" : "encripted_password_here"
}
},
"username" : "test_user",
"emails" : [{
"address" : "1#gmail.com",
"verified" : false
}],
"profile" : {
"packages" : [{
"packageId" : "67fmCMNTdqejFs7NE",
"name" : "package1"
"active" : true
}, {
"packageId" : "Dcn4PkmHNe8APuk73",
"name" : "package2"
"active" : true
}, {
"packageId" : "yvdXkPeNHEWwwLKjC",
"name" : "package2"
"active" : true
}]
}
}
I want set all active to false. What should I do? My current code is like (not working):
Meteor.users.update({ _id: Session.get('user_id') }, { $set: {'profile.packages.active': false} });
It cannot be done in a single query as there are many elements in the "packages" array. Even if you try the below query, only the first match will get updated in the current document and rest will remain same.
db.exp10.update({"profile.packages.active":true},{$set:{"profile.packages.$.active":false}},{multi:true})
Output :
{
"_id" : "AayujR3SLT5MtmTKf",
"createdAt" : ISODate("2015-09-18T07:19:05.069Z"),
"services" : {
"password" : {
"bcrypt" : "encripted_password_here"
}
},
"username" : "test_user",
"emails" : [
{
"address" : "1#gmail.com",
"verified" : false
}
],
"profile" : {
"packages" : [
{
"packageId" : "67fmCMNTdqejFs7NE",
"name" : "package1",
"active" : false
},
{
"packageId" : "Dcn4PkmHNe8APuk73",
"name" : "package2",
"active" : true
},
{
"packageId" : "yvdXkPeNHEWwwLKjC",
"name" : "package2",
"active" : true
}
]
}
}
So better we can do it using the below piece of code :
db.user.find({"profile.packages.active":true}).forEach(function(doc){
for( var count = 0; count < doc.profile.packages.length; count++ )
{
if( doc.profile.packages[count].active == true )
doc.profile.packages[count].active = false;
}
db.user.save(doc);
});
Output :
{
"_id" : "AayujR3SLT5MtmTKf",
"createdAt" : ISODate("2015-09-18T07:19:05.069Z"),
"services" : {
"password" : {
"bcrypt" : "encripted_password_here"
}
},
"username" : "test_user",
"emails" : [
{
"address" : "1#gmail.com",
"verified" : false
}
],
"profile" : {
"packages" : [
{
"packageId" : "67fmCMNTdqejFs7NE",
"name" : "package1",
"active" : false
},
{
"packageId" : "Dcn4PkmHNe8APuk73",
"name" : "package2",
"active" : false
},
{
"packageId" : "yvdXkPeNHEWwwLKjC",
"name" : "package2",
"active" : false
}
]
}
}
P.S :
If the collection has many documents, For better performance we can use Bulk Operations.
Is there any way to create schema for this type data:
"documents" : {
"54983c4c78c824eb0ac7a0d8" : {
"completed" : true
},
"54983c4c78c824eb0ac7a0dd" : {
"completed" : true
},
"54983c4c78c824eb0ac7a0d7" : {
"completed" : true
},
"54983c4c78c824eb0ac7a0de" : {
"completed" : true,
"comments" : [
{
"author" : "54973a31cfb18d60089e9403",
"text" : "hello"
}
]
}
}
How about this:
"documents":{[
{"id":54983c4c78c824eb0ac7a0d8,
"status":"completed"},
{"id":54983c4c78c824eb0ac7a0dd,
"status":"completed"},
{"id":54983c4c78c824eb0ac7a0d7,
"status":"completed"},
{"id":54983c4c78c824eb0ac7a0de,
"status":"completed",
"comments":[
{"author_id":54973a31cfb18d60089e9403,
"text":"hello"}]
}]}
Then you could query anything you want:
db.documents.find({"id":54983c4c78c824eb0ac7a0d8})
or by status:
db.documents.find({"status":"completed"})
Whether a user sends or receives a message, he/she should be able to archive the message for him/herself.
This .aggregate $or, however, only returns docs that the user is the recipient of ('to') that he/she has marked 'archive':'true'. It does accurately filter messages according to the 'value' Booleans.
Models.Messages.aggregate([
// Match documents
{ "$match": {
"$or" : [
{
"to": {
"$elemMatch": {
"username": 'userA',
"view.archive": true,
"view.bin": false
}
}
},
{
"from" : {
"$elemMatch" : {
"username" : 'userA',
"view.archive": true,
"view.bin": false
}
}
}
],
"$or": [
{ 'value.1': true },
{ 'value.2': true },
{ 'value.3': true },
{ 'value.4': false }
]
}},
// Unwind to de-normalize
{ "$unwind": "$to" },
{ "$unwind": "$from" },
// Match the array elements
{ "$match": {
"to.username": 'userA',
"to.view.archive": true,
"from.username": 'userA',
"from.view.archive": true
}},
// Group back all the elements of the original document
{ "$group": {
"_id": "$_id",
"from": { "$push": "$from" },
"to": { "$push": "$to" },
"message": { "$first": "$message" },
"updated": { "$first": "$updated" }
}},
// Sort by updated, most recent first (descending)
{"$sort": {"updated": -1}}
], function (err, docs) {
How could this be altered so that all the fields of both of the following messages are aggregated for userA:
{
"_id" : ObjectId("53e83867f316ea7f22fd3b2b"),
"updated" : ISODate("2014-08-11T03:29:06.000Z"),
"message" : "message1",
"value" : [
"1" : true,
"2" : false,
"3" : false,
"4" : false
]
"to" : [
{
"user" : ObjectId("53e835bd76e0d04318d8cc4e"),
"username" : "userA",
"_id" : ObjectId("53e83867f316ea7f22fd3b2c"),
"view" : {
"inbox" : false,
"outbox" : false,
"archive" : true,
"bin" : false
}
}
],
"from" : [
{
"user" : ObjectId("53e8360276e0d04318d8cc55"),
"username" : "userB",
"_id" : ObjectId("53e83867f316ea7f22fd3b2d"),
"view" : {
"inbox" : false,
"outbox" : true,
"archive" : false,
"bin" : false
}
}
],
"__v" : 5
}
{
"_id" : ObjectId("53e83867f316ea7f22fd3b2b"),
"updated" : ISODate("2014-08-11T03:29:06.000Z"),
"message" : "message2",
"value" : [
"1" : false,
"2" : true,
"3" : false,
"4" : false
]
"to" : [
{
"user" : ObjectId("53e8360276e0d04318d8cc55"),
"username" : "userB",
"_id" : ObjectId("53e83867f316ea7f22fd3b2c"),
"view" : {
"inbox" : true,
"outbox" : false,
"archive" : false,
"bin" : false
}
}
],
"from" : [
{
"user" : ObjectId("53e835bd76e0d04318d8cc4e"),
"username" : "userA",
"_id" : ObjectId("53e83867f316ea7f22fd3b2d"),
"view" : {
"inbox" : false,
"outbox" : true,
"archive" : true,
"bin" : false
}
}
],
"__v" : 5
}
You can't have two $or fields at the top level of your first $match object, so you need to wrap those in an $and array like the following if they both need to be satisfied:
{ "$match": {
$and: [{
"$or" : [
{
"to": {
"$elemMatch": {
"username": 'userA',
"view.archive": true,
"view.bin": false
}
}
},
{
"from" : {
"$elemMatch" : {
"username" : 'userA',
"view.archive": true,
"view.bin": false
}
}
}
]}, {
"$or": [
{ 'value.1': true },
{ 'value.2': true },
{ 'value.3': true },
{ 'value.4': false }
]
}
]
}}
There's a lot going on in your pipeline, so this may not be the only problem.