Mongoose Schema Of Nested Objects - mongodb

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"})

Related

Mongo Update just one item in an sub-document and add one item in the same sub document

This is the document in my collection
{
"_id" : ObjectId("5d766c18791adb12cc607d49"),
"name" : "myapp",
"openApp" : true,
"appDeveloper" : "Arun",
"environments" : [
{
"environment_id" : ObjectId("5d766c18791adb12cc607d45"),
"environment_name" : "production_env_updated",
"environment_type" : "prod",
"services" : [
{
"service_id" : ObjectId("5d766c18791adb12cc607d46"),
"service_name" : "some_updated",
"service_type" : "..."
},
{
"service_id" : ObjectId("5d766d45791adb12cc607d4a"),
"service_name" : "updated 2",
"service_type" : "..."
}
]
},
{
"environment_id" : ObjectId("5d766c18791adb12cc607d48"),
"environment_name" : "demo_env",
"environment_type" : "stage",
"services" : [
{
"service_id" : ObjectId("5d766d45791adb12cc607d4b"),
"service_name" : "perfectly new",
"service_type" : "perfect"
}
]
}
]
}
I wanted to run a query that would update only "service_id" : ObjectId("5d766c18791adb12cc607d46") within the services-array and then add a new service-object
I executed the below query and doesn't know how to move further
db.app_attributes.update ({"_id" : ObjectId("5d766c18791adb12cc607d49")},
{ '$set': {"environments.services.service_id" : ObjectId("5d766c18791adb12cc607d46") : {
"service_id" : ObjectId("5d766c18791adb12cc607d46"),
"service_name" : "sdfsdf",
"service_type" : "..."
}}}
)
If I understand correctly, you want to update the subdocument whose service_id is ObjectId("5d766c18791adb12cc607d46").
You can do it using the Filtered Positional Operator
db.app_attributes.update(
{"_id" : ObjectId("5d766c18791adb12cc607d49")},
{
$set: {
"environments.$[].services.$[element]": {
"service_id" : ObjectId("5d766c18791adb12cc607d46"),
"service_name" : "Updated Service Name",
"service_type" : "Updated Service Type"
}
}
},
{
arrayFilters: [
{"element.service_id": ObjectId("5d766c18791adb12cc607d46")}
],
multi: true
}
)

MongoDB 3.2 Update Field name in embedded array

Im trying to do a i migration in my MongoDB. I have updated a Field from Content -> StringContent. Now I want to update all records that exists with the new Field name.
This is how a document looks like.
{
"_id" : "c4af0b19-4c78-4e58-bbe5-ac9e5cce2c3f",
"Type" : "Onboarding",
"Cards" : [
{
"_id" : LUUID("3f328a1c-658d-ee4e-8f06-561760eb5be5"),
"Width" : 1,
"Title" : "",
"Type" : "Freetext",
"Description" : "",
"Content" : "This is a test" // -> "StringContent" : "This is a Test"
},
{
"_id" : LUUID("2f328a1c-658d-ee4e-8f06-561760eb5be5"),
"Width" : 1,
"Title" : "",
"Type" : "Freetext",
"Description" : "",
"Content" : "This is another test" //-> "StringContent" : "This is another Test"
}
],
"DocumentType" : "Template",
"History" : [
{
"Date" : ISODate("2017-07-13T12:03:01.620Z"),
"ByUserId" : LUUID("4ecaa6ca-2ce6-f84c-81f3-28f8f0256e6e")
}
],
"Name" : "Default Template"
}
I have created this script:
var bulk = db.getCollection('OnboardingPortal').initializeOrderedBulkOp(),
count = 0;
db.getCollection('OnboardingPortal').find({"DocumentType": "Template"}).
forEach(function(doc) {
doc.Cards.forEach(function(card) {
if(card.hasOwnProperty("Content")){
print(card);
bulk.find({"_id": doc._id, "Cards._id": card._id}).update(
{
$set: {"Cards.$.StringContent": card.Content}
});
bulk.find({"_id": doc._id, "Cards._id": card._id}).update(
{
$unset: {"Cards.$.Content": 1}
});
count += 2;
if(count % 500 == 0) {
bulk.execute();
bulk = db.getCollection('OnboardingPortal').initializeOrderedBulkOp();
}
}
});
});
if ( count % 500 !== 0 ){
bulk.execute();
}
This Does not update anything, but if I change bulk.operations -> to explicit set index on array like this, it will do the job. but only for one card :
bulk.find({"_id": doc._id, "Cards.1._id": card._id}).update(
{
$set: {"Cards.1.StringContent": card.Content}
});
bulk.find({"_id": doc._id, "Cards.1._id": card._id}).update(
{
$unset: {"Cards.1.Content": 1}
});
What am i missing in my script so this can iterates over several documents and change Content-> StringContent in each Card. ?
EDIT
I have added a bulk.getOperations(); in my script. this is what it returns. Should it not have replaced $ with index ?
/* 1 */
[
{
"originalZeroIndex" : 0.0,
"batchType" : 2.0,
"operations" : [
{
"q" : {
"_id" : "c4af0b19-4c78-4e58-bbe5-ac9e5cce2c3f",
"Cards._id" : "1c8a323f-8d65-4eee-8f06-561760eb5be5"
},
"u" : {
"$set" : {
"Cards.$.StringContent" : "This is a cool test"
}
},
"multi" : false,
"upsert" : false
},
{
"q" : {
"_id" : "c4af0b19-4c78-4e58-bbe5-ac9e5cce2c3f",
"Cards._id" : "1c8a323f-8d65-4eee-8f06-561760eb5be5"
},
"u" : {
"$unset" : {
"Cards.$.Content" : 1.0
}
},
"multi" : false,
"upsert" : false
},
{
"q" : {
"_id" : "c4af0b19-4c78-4e58-bbe5-ac9e5cce2c3f",
"Cards._id" : "1c8a322f-8d65-4eee-8f06-561760eb5be5"
},
"u" : {
"$set" : {
"Cards.$.StringContent" : "This is a test"
}
},
"multi" : false,
"upsert" : false
},
{
"q" : {
"_id" : "c4af0b19-4c78-4e58-bbe5-ac9e5cce2c3f",
"Cards._id" : "1c8a322f-8d65-4eee-8f06-561760eb5be5"
},
"u" : {
"$unset" : {
"Cards.$.Content" : 1.0
}
},
"multi" : false,
"upsert" : false
}
]
}
]

How to get only the objects meeting one criteria in mongodb?

I have example collection:
db.books.find()
{ "author" : "Coetzee", "is_favourite" : true, "version" : 1 }
{ "author" : "Coetzee", "is_favourite" : true, "version" : 1 }
{ "author" : "Coetzee", "is_favourite" : false, "version" : 2 }
{ "author" : "King", "is_favourite" : false, "version" : 2 }
{ "author" : "Cohen", "is_favourite" : true, "version" : 2 }
{ "author" : "Cohen", "is_favourite" : false, "version" : 3 }
{ "author" : "Picasso", "is_favourite" : true, "version" : 3 }
by running this:
db.books.aggregate([
{ $match: {"is_favourite":{ $ne: true}}},
{ $group: { _id: "$author"}}
])
I get the following:
{ "_id" : "Cohen" }
{ "_id" : "King" }
{ "_id" : "Coetzee" }
what should I do to get only the objects meeting "is_favourte": false?
In this particular case I'm interested in getting only "author": "King"
Assuming that you want author where is_favourite is always false, you could use this :
db.books.aggregate([
{
$group:{
_id:"$author",
is_fav:{
$push:"$is_favourite"
}
}
},
{
$match:{
is_fav:{
$nin:[
true
]
}
}
},
{
$project:{
_id:1
}
}
],{
allowDiskUse: true
})
returns
{ "_id" : "King" }

Mongodb : How should I get original Json structure after filter the records based on requirement?

I am new to mongodb.
I have a Json document in collection like :
{
"_id" : ObjectId("55abf32f358e3aca807f0e6a"),
"usercbid" : 1995492.0000000000000000,
"defaultnotifytype" : {
"status" : true,
"alert" : true,
"action" : true
},
"calendar" : {
"alert" : 2468.0000000000000000,
"action" : 13579.0000000000000000,
"status" : 123456.0000000000000000
},
"assignment" : [
{
"orgid" : {
"service" : "AVPN",
"adminemail" : "pl9129#att.com",
"notifytype" : {
"status" : true,
"alert" : true
},
"keytype" : "MCN",
"KeyValue" : "SK1383"
}
},
{
"orgid" : {
"KeyValue" : "DD3342",
"service" : "<all>",
"keytype" : "MCN"
}
},
{
"orgid" : {
"notifytype" : {
"optout" : true
},
"keytype" : "MCN",
"keyvalue" : "<all>",
"service" : "MVPN"
}
},
{
"order" : {
"date" : "2015-03-15",
"adminemail" : "abc.com",
"notifytype" : {
"alert" : true
},
"id" : 123456.0000000000000000
}
},
{
"order" : {
"id" : 135246.0000000000000000,
"date" : "2015-03-17",
"adminemail" : "abc.com"
}
}
]
}
I would like to filter above json document with following condition:
var result = db.subscription.aggregate(
[ { $unwind: "$assignment" }
, {$match : {$or:
[
{
"assignment.order.id" : 123456
},
{
"assignment.orgid.keytype" : { $in: ["MCN"]}
,"assignment.orgid.KeyValue" : { $in: ["<all>","SK1383"]}
,"assignment.orgid.service" : { $in: ["<all>","AVPN"]}
}
]
}
}
,{$group: {_id: "$_id", assignment: {$push: "$assignment"}}}
// ,{$project : { usercbid : $usercbid, defaultnotifytype : 1, calendar : 1, assignment: 1} }
]
)
printjson(result);
Result of above query is :
{
"result" : [
{
"_id" : ObjectId("55abf32f358e3aca807f0e6a"),
"assignment" : [
{
"orgid" : {
"service" : "AVPN",
"adminemail" : "pl9129#att.com",
"notifytype" : {
"status" : true,
"alert" : true
},
"keytype" : "MCN",
"KeyValue" : "SK1383"
}
},
{
"order" : {
"date" : "2015-03-15",
"adminemail" : "pl9129#att.com",
"notifytype" : {
"alert" : true
},
"id" : 123456
}
}
]
}
],
"ok" : 1
}
But my final result lost the following original content:
"usercbid" : 1995492.0000000000000000,
"defaultnotifytype" : {
"status" : true,
"alert" : true,
"action" : true
},
"calendar" : {
"alert" : 2468.0000000000000000,
"action" : 13579.0000000000000000,
"status" : 123456.0000000000000000
},
How should I append above original content with filtered records?
Thanks,
$Fisrt is the operator which helps you getting the required output.
When you do a $Group, the result of the $Group pipeline operator contains only those fields which are specified inside the $Group pipeline operator.
So, from your query we can notice that you are grouping based on "_Id" and you are selecting only "assignment" key field, so the OUTPUT of this group pipeline operator will contain only those 2 fileds ( "_ID" and "assignment" ).
To make sure that the other left out feilds ( usercbid, defaultnotifytype , calendar ) to be part of the $Group pipeline output, we need to mention that explicitly in the Group pipeline using $First as below :
{ $group: { _id: "$_id", assignment: {$push: "$assignment"},
usercbid : { $first : "usercbid"} ,
defaultnotifytype : { $first : "defaultnotifytype" } ,
calendar : { $first : "calendar"}
}
}
$First Returns the value that results from applying an expression to the first document in a group of documents that share the same group by key.
Please check the below query, it will help you in fetching the required output :
var result = db.subscription.aggregate(
[ { $unwind: "$assignment" }
, { $match : {$or:
[
{
"assignment.order.id" : 123456
},
{
"assignment.orgid.keytype" : { $in: ["MCN"]}
,"assignment.orgid.KeyValue" : { $in: ["<all>","SK1383"]}
,"assignment.orgid.service" : { $in: ["<all>","AVPN"]}
}
]
}
}
,{ $group: { _id: "$_id", assignment: {$push: "$assignment"},
usercbid : { $first : "usercbid"} ,
defaultnotifytype : { $first : "defaultnotifytype" } ,
calendar : { $first : "calendar"}
}
}
]
).pretty();

MongoDB .find with multiple $or statements, syntax error 'unexpected token ]'?

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) {