Push hierarchical array in MongoDB - arrays

I have the following document:
{
"_id":"575322d9585095d9929554ba",
"Level1":{
"Level2":[
{
"Level3a":{
"Level4":{
"Level5":{
"name":"John",
"surname":"Matthew"
}
}
}
},
{
"Level3a":{
"Level4":{
"Level5":{
"name":"Emma",
"surname":"Jackson"
}
}
}
}
]
}
}
I need to insert the new name and surname at Level5. I tried the $push method but I got the error that the dotted field .. is not valid for storage:
db.names.update({ "_id":"575322d9585095d9929554ba" },
{
$push: {
"Level1.Level2":
{ $each: [ { "Level3a.Level4.Level5.name": "Greg" },
{ "Level3a.Level4.Level5.surname": "Cook" }] } } } )
It seems that push does not allow the inserting new data in hierarchical arrays or I am wrong?

There is an issue with your query as $each is used to add multiple values to same array....
As we are going to add only one entry to array we don't need to use $each
so query looks like this:
db.vnenad.update({
"_id" : "575322d9585095d9929554ba"
},
{
$push : {
"Level1.Level2" : {
"Level3a" : {
"Level4" : {
"Level5" : {
"name" : "johnny",
"surname" : "rambo"
}
}
}
}
}
})
as I was debbuging your query I decided to create variable with document to insert inside an array, then it was easier for me to adjust your query - please see below:
var doc = {
"Level3a" : {
"Level4" : {
"Level5" : {
"name" : "johnny",
"surname" : "rambo"
}
}
}
}
db.vnenad.update({
"_id" : "575322d9585095d9929554ba"
},
{
$push : {
"Level1.Level2" : doc
}
})

Related

Issue searching an array of ObjectIds in an aggregate function

I'm trying to do something which should be pretty straightforward. The aggregrate pipeline allows you to pass documents through stages in sequence. For example, I can filter out some documents and pass the documents I want to the next stage. This can be accomplished with $match. Then I want to take the remaining documents and group them by a field to check for duplicates. But I am having major issues with this. This is what I have tried:
db.my_fields.aggregate(
{ '$match' : { related_code_id: { "$in" : [ BSON::ObjectId('5cddd0143ed1495e5c000008'),BSON::ObjectId('5cddd0143ed1495e5c000010')] } } },
{ '$group' : { _id: { 'field' : '$field', 'field_type_id' : '$field_type_id' }, count: { '$sum' : 1} } },
{'$match' : { count: {'$gt' : 1} } }
)
The query works fine except for the first $match. Inside the $in statement, I am getting this error:
2019-05-17T18:47:56.602-0400 E QUERY [js] SyntaxError: missing ] after element list #(shell):2:95
It is complaining about this part right here:
BSON::ObjectId('5cddd0143ed1495e5c000008'),BSON::ObjectId('5cddd0143ed1495e5c000010')
How can I resolve this issue and achieve my goal of getting this basic query working?
Converting the ObjectId to BSON isn't needed:
https://docs.mongodb.com/manual/reference/method/db.collection.find/#query-using-operators
// ...
'$match': {
related_code_id: {
"$in": [
ObjectId('5cddd0143ed1495e5c000008'),
ObjectId('5cddd0143ed1495e5c000010')
]
}
}
// ...
If you are using Mongoose as ORM, you can solve it as follows.
db.my_fields.aggregate(
{ '$match' : { related_code_id: { "$in" : [ mongoose.Types.ObjectId('5cddd0143ed1495e5c000008'),mongoose.Types.ObjectId('5cddd0143ed14 95e5c000010')] } } },
{ '$group' : { _id: { 'field' : '$field', 'field_type_id' : '$field_type_id' }, count:
{ '$sum' : 1} } },
{'$match' : { count: {'$gt' : 1} } }
)

Add array values into MongoDB where element is not in array

In MongoDB, this is the simplified structure of my account document:
{
"_id" : ObjectId("5a70a60ca7fbc476caea5e59"),
"templates" : [
{
"name" : "Password Reset",
"content" : "AAAAAAAA"
},
{
"name" : "Welcome Message",
"content" : "BBBBBB"
}
]
}
There's a similar default_templates collection
let accnt = await Account.findOne({ _id: req.account._id }, { templates: 1 });
let defaults = await DefaultTemplate.find({}).lean();
My goal is to find the missing templates under account and grab them from defaults. (a) I need to upsert templates if it doesn't exist in an account and (b) I don't want to update a template if it already exists in an account.
I've tried the following:
if (!accnt.templates || accnt.templates.length < defaults.length) {
const accountTemplates = _.filter(accnt.templates, 'name');
const templateNames = _.map(accountTemplates, 'name');
Account.update({ _id: req.account._id, 'templates.name' : { $nin: templateNames } },
{ '$push': { 'templates': { '$each' : defaults } } }, { 'upsert' : true },
function(err, result) {
Logger.error('error %o', err);
Logger.debug('result %o', result);
}
);
}
This succeeds at the upsert but it will enter all default templates even if there's a matching name in templateNames. I've verified that templateNames array is correct and I've also tried using $addToSet instead of $push, so I must not understand Mongo subdoc queries.
Any ideas on what I'm doing wrong?
Edit: I've gotten this to work by simply removing elements from the defaults array before updating, but I'd still like to know how this could be accomplished with Mongoose.
You can try with bulkWrite operation in mongodb
Account.bulkWrite(
req.body.accountTemplates.map((data) =>
({
updateOne: {
filter: { _id: req.account._id, 'templates.name' : { $ne: data.name } },
update: { $push: { templates: { $each : data } } },
upsert : true
}
})
)
})

Meteor element in array of a array

Basically wanted to push data within array of array i.e publicHolidays is outer array and holidayList is inner array. This is mongodb schema looking right now.
"publicHolidays" : [
{
"location" :"pune"
"year" : 2016
"holidayList"[
{
"holidayDate" :"2016-11-09",
"holidayName":"Diwali"
}
]
}
]
I am expecting below schema,wanted to push data in holidayList.
"publicHolidays" : [
{
"location" :"pune"
"year" : 2016
"holidayList"[
{
"holidayDate" :"2016-11-09",
"holidayName":"Diwali"
}
{
"holidayDate" :"2016-1-09",
"holidayName":"padwa"
}
{
"holidayDate" :"2016-12-10",
"holidayName":"holi"
}
]
}
]
Solved issue:
//Add Holidays in Exist Location
'companySettings.updatePublicHolidays'(formValues){
CompanySettings.update(
{
'_id': formValues.UniqueID,
'publicHolidays' : {$elemMatch : {'location': formValues.holidaysLocation,'year': formValues.holidayYear} }
},
{
$push : {'publicHolidays.$.holidayList':
{
'holidayDate' : formValues.leaveDate ,
'holidayName' : formValues.holidayName
}
}
}
);
},

ElasticSearch - why ScriptDocValues returns unique values?

I have simple mapping - one string field and one string[] field.
The array of strings contains duplicate values, and I get those duplicate values in query:
{ "query" : { "term" : {"id" : "579a252585b8c5c428fa0a3c"} } }
Returns a single valid hit:
{
"id" : "579a252585b8c5c428fa0a3c",
"touches" : [ "5639abfb5cba47087e8b4571", "5639abfb5cba47087e8b4571", "5639abfb5cba47087e8b4571", "5639abfb5cba47087e8b457b", "5639abfb5cba47087e8b457b"
}
But in metric script aggregation:
"aggs": {
"path": {
"scripted_metric": {
"map_script": "_agg['result'] = doc['touches'].values"
}
}
}
retuns
"aggregations" : {
"path" : {
"value" : [ { }, {
"result" : [ "5639abfb5cba47087e8b4571", "5639abfb5cba47087e8b457b" ]
}, { }, { }, { } ]
}
}
that element is org.elasticsearch.index.fielddata.ScriptDocValues$Strings, casting it toString() returns a json-encoded 2-element array.
So, the question:
Why does ScriptDocValues$Strings return only unique array values and how to get the initial array in script aggregation?
Thanks.
UPD
I found that for numerical values (in particular floats) everything works perfect.

$push in MongoDb not working?

my schema looks like this:
var exampleSchema = newSchema({
profile:{
experience :[{
exp : String
}]
}
});
this is the codes to update experience in profile collection:
exampleSchema.statics.experience = function (id,experience, callback){
var update = {
$push: {
'profile.experience': experience
}
}
this.findByIdAndUpdate(id,update,function(err) {
if (err) {
callback(err);
} else {
callback(null);
}
})
I was getting error like The field 'profile.experience' must be an array but is of type String in document {_id: ObjectId('5653f1d852cf7b4c0bfeb54a')}[object Object]
console.log(experience) is equal to
{ exp: 'jlkjlkjlk' }
my collection should look like this:
experience:[
{
exp : "YYYY"
},
{
exp:"xxxx"}
]
Imagine that you have this collection:
/* 1 */
{
"_id" : ObjectId("565425e862760dfe14339ba8"),
"profile" : {
"experience" : [
{
"exp" : "Experto"
}
]
}
}
/* 2 */
{
"_id" : ObjectId("565425f562760dfe14339ba9"),
"profile" : {
"experience" : {
"exp" : "Experto"
}
}
}
/* 3 */
{
"_id" : ObjectId("5654260662760dfe14339baa"),
"profile" : {
"experience" : "Experto"
}
}
If you try (update doc /* 2 */):
db.profile.update(
{ _id: ObjectId("565425f562760dfe14339ba9") },
{ $push: { "profile.experience" : { exp : "Intermediate" } } }
)
You get this error:
The field 'profile.experience' must be an array but is of type Object
in document {_id: ObjectId('565425f562760dfe14339ba9')}
And if you try (update doc /* 3 */):
db.profile.update(
{ _id: ObjectId("5654260662760dfe14339baa") },
{ $push: { "profile.experience" : { exp : "Intermediate" } } }
)
You will get:
The field 'profile.experience' must be an array but is of type String
in document {_id: ObjectId('5654260662760dfe14339baa')}
i changed Schema like this
experience : [{type:String,exp:String}],
my update object looks like this
var update = {
$push: {
'profile.experience': san.exp
}
};
san looks like this :{ exp: 'YYY' }
Inside mongoose collectionlooks like this used RoboMongo
"experience" : [
"experienced in XXX",
"YYY"
],
$push: {
'profile.experience': experience
}
Remove .exp.
First you have to check you declared your field as an array like this(look at field products):
shop = {
'name': "Apple Store",
'description': "",
'direction': "",
'contact': "",
'products':[]
}
Now if you want to add something to the field products using $push
product = {
'name': "Iphone 6",
'description': "Iphone model 6, 64GB",
'price': 700,
'count': 3
}
myquery = { "name" : "Apple Store" }
obj ={"$push":{"products":{"$each": [product]}}}
db.collection.update_one(myquery,obj)
This code is provided for PyMongo framework. To use in MongoDB directly replace update_one by update. Mongo resource
You may use $set instead of $push which might work.
$set: {
'profile.experience': experience
}
are you searching for adding multiple values into single field then use this one.
write this one your model or schema:
arrayremarks:[{remark: String}]
then write in your controller:
module.exports.addingremarks = (req, res) => {
let casenum=JSON.parse(JSON.stringify(req.body.casenum).replace(/"\s+|\s+"/g,'"'))
var rem={remark:"Suman macha"}
Inwart.update( { 'casenum': casenum },{ $push: { arrayremarks:rem} } ,function (err, inwarts) {
if (err)
return console.error(err);
res.send(inwarts);
}
)
}

Resources