Meteor $push multipoint array - arrays

I set coordinates in a geolocation array:
Crowds.insert({
location: {"type": "MultiPoint","coordinates":
[[1, 1]]
}
});
Crowds._ensureIndex({ location: "2dsphere" });
Then I try to add value. To do so I make a §push to add new value in "coordinates" array:
Crowds.update(
{ _id: crowd[0]._id },
{ $push: { location: { "coordinates": [ 2, 2 ]
}}}
);
I get the folling error:
Exception in Mongo write: TypeError: object is not a function
It seems that I am not updating coordinates array the proper way... I tried various combinations but cannot find how to add value in a nested array...
Please help ;) Thanks

Is there a typo there?
crowd[0]._id
"crowd" is singular there, yet you're calling [0] as if it's an array.
Should it be:
crowds[0]._id

I think I found the problem, and actually I didn't ask the question well... sorry
The following code returned error:
Crowds.update(
{ _id: '123' },
{ $inc: { people: 1 } },
{ $push: { "location.coordinates": [ Meteor.user().profile.location.coords.longitude, Meteor.user().profile.location.coords.latitude ],
{ $set: { modified: new Date().valueOf() } },
function(error){
return "Update error: " + error;
}
);
But it works with:
Crowds.update(
{ _id: '123' },
{ $inc: { people: 1 } },
{ $set: { modified: new Date().valueOf() } },
function(error){
return "Update error: " + error;
}
);
Crowds.update(
{ _id: crowd[0]._id },
{ $push: { "location.coordinates": [ Meteor.user().profile.location.coords.longitude, Meteor.user().profile.location.coords.latitude ]
}},
function(error){
return "Update error: " + error;
}
);
It seems that $push needs to be used alone, tell me if I am wrong in diagnostic ;)

Related

Update nested array object value by replacing substring of that object property

I have the following set of data in my MongoDB collection called orders:
{
"_id" : ObjectId("618e0e1b17687316dcdd6246"),
"groupUID": "abc",
"orderData" : {
"charges" : {
"total" : 18480.0,
"subtotal" : 13980.0
},
"items" : [
{
"name" : "Chocolate cookies",
"imageURL": "domainURL2.com/cookies"
},
{
"name" : "Chocolate muffins",
"imageURL": "domainURL2.com/muffins"
}
]
}
}
Now I want to update the imageURL substring part of "domainURL2" to "domainURL1" field in every document of this collection. I have the following query so far:
db.orders.update(
{
"groupUID" : "abc"
},
{ "$set": { "orderData.items.$.imageURL":"myURL.com" } } )
I also have the query in JavaScript form but I want this to be in pure Mongo query. So the query below will not do it for me unfortunately.
db.getCollection("orders").find({"groupUID" : "abc"}).forEach(function(aRow) {
if (aRow.orderDetails !== undefined) {
var updated = false;
aRow.orderData.items.forEach(function(item) {
item.imageURL = item.imageURL.replace("eddress/", "noknok-app/");
})
db.getCollection("orders").save(aRow);
}
});
I want to update all records' imageURL field's substring part. I am unable to figure out the rest of the query. Can anyone please help me?
My answer may look complex (Welcome for suggestion/improvement).
Work the update with Aggegration Pipeline.
$set - Update orderData.items field.
1.1. $map - Iterate orderData.items and returns new array.
1.1.1. $mergeObjects - Merge current object and imageURL field from 1.1.1.1.
1.1.1.1. $cond - With $regexMatch to find the imageURL starts with "domainURL2.com".
1.1.1.2. If true, then replace "domainURL2.com" with "domainURL1.com".
1.1.1.3. If false, remain existing value.
db.collection.update({
"groupUID": "abc"
},
[
{
"$set": {
"orderData.items": {
$map: {
input: "$orderData.items",
in: {
$mergeObjects: [
"$$this",
{
imageURL: {
$cond: {
if: {
$regexMatch: {
input: "$$this.imageURL",
regex: "^domainURL2.com"
}
},
then: {
$concat: [
"domainURL1.com",
{
$arrayElemAt: [
{
$split: [
"$$this.imageURL",
"domainURL2.com"
]
},
-1
]
}
]
},
else: "$$this.imageURL"
}
}
}
]
}
}
}
}
}
])
Sample Mongo Playground
Another approach is using $replaceOne (suggested by #rickhg12hs) which will be much easier.
$replaceOne to replace for 1.1.1.1.
db.collection.update({
"groupUID": "abc"
},
[
{
"$set": {
"orderData.items": {
$map: {
input: "$orderData.items",
in: {
$mergeObjects: [
"$$this",
{
imageURL: {
$replaceOne: {
input: "$$this.imageURL",
find: "domainURL2.com",
replacement: "domainURL1.com"
}
}
}
]
}
}
}
}
}
])
Sample Mongo Playground ($replaceOne)

mongoDB sum of array lengths and missing fields [duplicate]

This question already has answers here:
MongoDB - The argument to $size must be an Array, but was of type: EOO / missing
(3 answers)
Closed 3 years ago.
I have a simple document that stores arrays of objects for a user, and I am looking to get a sum of these arrays and a total of all; the challenge is that some documents are missing fields that other documents have, and this causes my aggregate query to fail.
Document looks like this.
{
name: '',
type: '',
cars: [],
boats: [],
planes: []
}
Some people do not have boats or planes...and those documents might look like
{
name: '',
type: '',
cars: []
}
So when I run my aggregate
[
{
'$match': {
'type': 'big_spender'
}
}, {
'$project': {
'name': '$name',
'cars': {
'$size': '$cars'
},
'boats': {
'$size': '$boats'
},
'planes': {
'$size': '$planes'
}
}
}, {
'$addFields': {
'total_vehicles': {
'$add': [
'$cars', '$boats', '$planes'
]
}
}
}
]
I get the error: "The argument to $size must be an array, but was of type: missing"
I am pretty sure I can use $exists to avoid this problem, and return a 0, but I have no idea what that syntax might look like.
I need to return a 0 for arrays that don't exist so when i add them for totals, I get a correct total and no errors.
Any help appreciated.
Use $ifNull aggregation operator. It will replace the field with blank array if it does not exists.
[
{ '$match': { 'type': 'big_spender' }},
{ '$project': {
'name': '$name',
'cars': { '$size': '$cars' },
'boats': { '$size': { '$ifNull': ['$boats', []] }},
'planes': { '$size': { '$ifNull': ['$planes', []] }}
}},
{ '$addFields': {
'total_vehicles': {
'$add': [
'$cars', '$boats', '$planes'
]
}
}}
]

How to update object inside array inside object?

I have the following Mongooose schema:
{
_id: {
type: String,
required: true
},
semesters: [
{
_id: {
type: String,
required: true
},
grades: [
{
subject: String,
literalGrade: String,
grade: Number,
credits: Number
}
]
}
]
}
I want to be able to update one grade that is inside semester's grades object using its id. I tried using MongoDb new multiple positional operator to no avail.
This is my current snippet:
User.findOneAndUpdate(
{
_id: req.params.user_id,
"semesters._id": req.params.semester_id
},
{
$set: {
"semesters.$[x].grades.$[y].subject": req.body.grades.subject,
"semesters.$[x].grades.$[y].literalGrade": req.body.grades.literalGrade,
"semesters.$[x].grades.$[y].grade": req.body.grades.grade,
"semesters.$[x].grades.$[y].credits": req.body.grades.credits
}
},
{
arrayFilters: [
{ "x._id": req.params.semester_id },
{ "y._id": req.params.grade_id }
]
},
(err, user) => {
if (err) return res.json(err);
res.send({
message: "Updated grade",
data: user
});
}
);
Couldn't get any results with the MongoDb positional operator, but found a way to programmatically do it with the help of Naing Lin Aung's answer. Here is the solution:
User.findOne(
{
_id: req.params.user_id,
"semesters.grades._id": req.params.grade_id
},
{ "semesters.$.grades": 1 },
(err, user) => {
if (err) return res.json(err);
let grades = user.semesters[0].grades;
let index = null;
for (let t in grades) {
if (grades[t]._id == req.params.grade_id) {
index = t;
break;
}
}
let grade = grades[index];
grade.subject = req.body.grades.subject;
grade.literalGrade = req.body.grades.literalGrade;
grade.grade = req.body.grades.grade;
grade.credits = req.body.grades.credits;
user.save(function(err) {
if (err) return res.json(err);
res.json({
message: "Updated grade",
data: user
});
});
}
);
You can take advantage of $[] syntax with arrayFilters
refer this link : https://docs.mongodb.com/manual/reference/operator/update/positional-all
db.col.update(
{ _id: req.params.user_id },
{ $set: { "semesters.$[cond1].grades.$[cond2].subject": req.body.grades.subject } },
{ arrayFilters: [ { "cond1._id": req.params.semester_id }, { "cond2._id": req.params.grade_id } ] })
You can similarly update other fields in $set

Remove id from array of objects in mongodb

I try to delete ObjectID in array of ObjectId.
My model:
let directoryCollection = new Schema(
{
email: { type: String },
directory: [{
name: { type: String },
list: [ {type: Schema.ObjectId} ]
}]
},
{collection: 'directory'}
);
I have a array of ObjectID in list.
My code for delete index in my array:
let id = mongoose.Types.ObjectId(req.body.id);
directoryModel.update({'email': email, 'directory.name': oldDirectory}, {$pull: {'directory.list': id} }, function (req, result) {
console.log(result);
res.json('ok');
});
But the result is:
{ ok: 0, n: 0, nModified: 0 }
Email variable and oldDirectory variable ara correct.
My ID is: 5b5e5f34cfcd3906c8e6aa20
Same in my database:
What is the problem ?
Thanks you !
Try this, Correct syntax to $pull from array of objects
directoryModel.update(
{ "email": email, "directory": { "$elemMatch": { "name": oldDirectory } } },
{ "$pull": { "directory.$.list": id } }
})

Count an array inside an array and then sum them MongoDB NodeJS

I have an object that has an array of page objects and each page object has an array of questions.
Ex object:
{
Id: 1,
UserId: 14,
Deleted: false,
Collaborators: [],
Title: "Awesome",
Pages: [{
Id: 1,
Title: 'Jank',
Questions: [
{ Id: 1, Content: 'Ask me about it' },
{ Id: 2, Content: 'Ask me about it again' }
]
}, {
Id: 2,
Title: 'Janker',
Questions: [
{ Id: 1, Content: 'Tell me about it' },
{ Id: 2, Content: 'Tell me about it again' }
]
}]
}
What I am trying to do is to get a count of all the questions for the entire bas object. I am not sure how to do that. I have tried to use aggregate and $sum the total questions and then do another function to $sum those all together to get a total for the entire object. Unfortunately my $sum is not working like I thought it would.
Ex code (nodejs):
var getQuestionCount = function(id) {
var cursor = mongo.collection('surveys').aggregate([{
$match: {
$or: [{
"UserId": id
}, {
"Collaborators": {
$in: [id]
}
}]
}
}, {
$match: {
"Deleted": false
}
}, {
$unwind: "$Pages"
},
{ $group: { _id: null, number: { $sum: "$Pages.Questions" } } }
], function(err, result) {
//This log just gives me [object Object], [object Object]
console.log('q count ' + result);
});
}
Any idea how to do this? My end result from the example object above would ideally return 4 as the question count for the whole object.
I'd try following shell query.
db.collection.aggregate([
// filter out unwanted documents.
{$match:{Id: 1}},
// Unwind Pages collection to access Questions array
{$unwind:"$Pages"},
// Count items in Questions array
{$project:{count: {$size:"$Pages.Questions"}}},
// Finally sum items previously counted.
{$group:{_id:"$_id", total: {$sum: "$count"}}}
])
Based on your sample document, it should return correct count of Questions.
{
"_id" : ObjectId("57723bb8c10c41c41ff4897c"),
"total" : NumberInt(4)
}

Resources