Mongoose - inserting a subdocument into another subdocument using push? [duplicate] - javascript

I need to push multiple values into an array in mongoose using one call. I tried doing it using a smaller array but the array is getting inserted as a sub-array.
var kittySchema = new mongoose.Schema({
name: String,
values: [Number]
});
var Kitten = db.model('Kitten', kittySchema);
Kitten.update({name: 'fluffy'},{$push: {values:[2,3]}},{upsert:true},function(err){
if(err){
console.log(err);
}else{
console.log("Successfully added");
}
});
The result of the calling the above code thrice gives the below result:
{ "_id" : ObjectId("502b0e807809d79e84403606"), "name" : "fluffy", "values" : [ [ 2, 3 ], [ 2, 3 ], [ 2, 3 ] ] }
Whereas what I want is something like this:
{ "_id" : ObjectId("502b0e807809d79e84403606"), "name" : "fluffy", "values" : [ 2, 3 ,2 ,3, 2, 3] }
Another thing I noticed was that the type in the array (values) is specified as Number, then wouldnt the 'strict' option ensure that anything other than Numbers are not inserted ? In this case another array is being allowed to be inserted.

(Dec-2014 update) Since MongoDB2.4 you should use:
Kitten.update({name: 'fluffy'}, {$push: {values: {$each: [2,3]}}}, {upsert:true}, function(err){
if(err){
console.log(err);
}else{
console.log("Successfully added");
}
});

Deprecated see other solution below using $push $each
Your example is close, but you want $pushAll rather than $push to have each value added separately (rather than pushing another array onto the values array):
var Kitten = db.model('Kitten', kittySchema);
Kitten.update({name: 'fluffy'},{$pushAll: {values:[2,3]}},{upsert:true},function(err){
if(err){
console.log(err);
}else{
console.log("Successfully added");
}
});

Or use the $each modifier with $addToSet:
https://docs.mongodb.com/manual/reference/operator/update/addToSet/#each-modifier
// Existing tags array
{ _id: 2, item: "cable", tags: [ "electronics", "supplies" ] }
// Add "camera" and "accessories" to it
db.inventory.update(
{ _id: 2 },
{ $addToSet: { tags: { $each: [ "camera", "accessories" ] } } }
)

Currently, the updated doc doesn't support $pushAll. It seems to have been deprecated.
Now the good choice is to use the combination of $push & $each
an example:
//User schema: {uid: String, transaction: [objects] }
const filter = {"uid": uid};
const update = {
$push: {
transactions: {$each: dataarr}
}
}
User.updateOne(filter, update, {upsert:true}, (err) => {
if(err){
console.log(err)
}
})
pass {upsert: true} at options to insert if the filter returns false.

Related

Mongoose array filtering and returning filtered array

My document have field roomname and field users which is an array:
['name1', 'name2', 'name3', 'name4' ,'name5' ,'name6' ,'name7']
How can I get filtered array of users from 'name2' to 'name5'?
I get from 'name1' to 'name7' array by coding :
roommodel.find({roomname:'room1'},'users').then(res=>{
console.log(res)
})
When there is less number of users like this one then there is a way:
let filteredusers=res.slice(1,4).map(i=>return i)
If there is huge amount of arrays it may slowdown server. I want to know if there is a direct method.
You can use it $nin Condition in Mongodb Query Like this,
roommodel.find({
roomname:'room1',
username: { $nin: [ 'name1', 'name7' ] }},'users')
.then(res=>{
console.log(res)
})
You can use Aggregation framework. Note that you will have to pass the input of all the indexes of users array that you want to be returned.
$match to filter relevant document
$map to iterate over the input array of indexes
$arrayElemAt to return the element from users array by the index
roommodel.aggregate([
{
"$match": {
"roomname": "room1"
}
},
{
"$set": {
"users": {
"$map": {
"input": [
2,
3,
4
],
"in": {
"$arrayElemAt": [
"$users",
"$$this"
]
}
}
}
}
}
])
Working example

Is there any way to pass array of indexes to mongodb and get elements from array at that indexes

I have an mongodb doc with an array of 100 elements and I want to get multiple elements from this array at given indexes given in query array.
example :
let query = [2,3,5,6,7,4,44,32,71];
So, I want to get elements in array in mongodb doc at indexes given in query array.
If you want filter data on mongo side, you can do like this.
db.getCollection('feed').find({
"_id" : {
"$in" : [
ObjectId("55880c251df42d0466919268"),
ObjectId("55bf528e69b70ae79be35006")
]
}
});
If not,
const filteredResult = items.filter(item => query.includes(item._id));
console.log(filteredResult);
there's no built-in mongodb operator that can support your requirement out of the box but... you can achieve it with a very difficult to read aggregation pipeline like this:
var query = [1, 3, 5]
db.Collection.aggregate(
[
{
$match: { "_id": ObjectId("5fd33ddd23505e1538b96116") }
},
{
$set: {
Array: {
$map: {
input: {
$filter: {
input: {
$map: {
input: "$Array",
as: "x",
in: {
Position: { $add: [{ $indexOfArray: ["$Array", "$$x"] }, 1] },
Value: "$$x"
}
}
},
as: "xx",
cond: { $in: ["$$xx.Position", query] }
}
},
as: "xxx",
in: "$$xxx.Value"
}
}
}
}
])
https://mongoplayground.net/p/_b1hzeUPlmu

How to find documents which are contains one or more elements of the search array in MongoDB?

I have a database in MongoDB, Here is sample collection of it.
[
{
id:123,
name: "name1",
likes: ["swim","run","walk"]
},
{
id:123,
name: "name1",
likes: ["swim","hike","run"]
},
{
id:123,
name: "name1",
likes: ["talk","run","sing"]
}
]
Then I have another array contains the search keywords
["hike","talk"]
So I need result like this.
{
id:123,
name: "name1",
likes: ["swim","hike","run"]
},
{
id:123,
name: "name1",
likes: ["talk","run","sing"]
}
Help me to solve this. I use mongoose ODM and express.js
You can use the $in operator. documentation
MyModel.find({likes : {$in : ['hike', 'talk']}}, (err, data) => {
if (err) {
console.log(err);
} else {
console.log(data);
}
});
You can use $or operator to see if any one of multiple queries in array is true. So for above code, you can query like:
db.collection.find({$or:[{likes:"hike"},{likes:"talk"}]})
Which says find all the entries in our db which satisfy that either of the conditions (hike exist in our like array or talk exists in our like array) is satisfied.

update array of object with multiple condition in mongoose failed

[{
"date": "18/12/2010",
"babies": [{
"id":1,
"name": "James",
"age": 8,
}, {
"id":2,
"name": "John",
"age": 4,
}]
}]
I want to set the age of John to 10 but failed. I have to do multi condition to be more specified.
Babies.update({"date":date, 'babies.id': 1}, {'$set': {age:10}, function(err, response){
res.json(response);
})
The first condition is date and the second condition is the array of object of babies, which in this case it's the id. Above query has no error and no effect, where did I do wrong?
I debug with doing this query
Babies.find({'babies.id': 1}, function(err, response){
res.json(response);
})
and it couldn't find the correct target, maybe that's the problem
Use {'$set': {'babies.$.age':10}} instead of {'$set': {age:10}}.
Babies.update({"date":date, 'babies.id': 1},
{'$set': {
'babies.$.age':10
}
},
function(err, response){
res.json(response);
})
The positional $ operator identifies an element in an array to update without explicitly specifying the position of the element in the array.
Refer to MongoDB Positional Operator for more information.
Instead of passing only object of field value {age:10} in $set flag, Pass the value in format of Array.index.field. So it would become like this -
{ $set: { 'babies.$.age': 10 } }

Mongo, match documents who's _id is in an array as part of a subdocument

Using MongoDB, I want to find all documents in one collection who's _id shows up in an array of sub-documents in another collection. Using the $in operator doesn't really work here, because I'm only trying to match against a single value in the sub-document.
Suppose I have the following document from db.foos:
{ _id: 1, foo: [ { bar_id: 1 }, { bar_id: 3 } ] }
and the following collection of db.bars:
{ _id: 1, foo: "bar" }
{ _id: 2, foo: "abr" }
{ _id: 3, foo: "rab" }
I want to find all documents in db.bars who's _id can be found in the foo array (returning db.bars with _id 1 and 3, in this case). Something like this:
var foos = db.foos.findOne( { _id: 1 } )
db.bars.find( _id: { $in: foos.foo.bar_id } )
Of course, that won't work. How would I go about accomplishing this?
You can use the collection.distinct method to get distinct _id values from the foo
db.bars.find({ '_id': { '$in': db.foos.distinct('foo.bar_id', {'_id': 1}) }})
Demo:
> db.foos.distinct('foo.bar_id', {'_id': 1})
[ 1, 3 ]
> db.bars.find({ '_id': { '$in': db.foos.distinct('foo.bar_id', {'_id': 1})}})
{ "_id" : 1, "foo" : "bar" }
{ "_id" : 3, "foo" : "rab" }

Categories