Mongo cyclic dependency detected while creating index - javascript

I have a data with structure like this:
And I try to write a query $near. For this query, I have to create index, but I get error cyclic dependency detected . Here is my code:
define model
var answers = new Schema({
countdown: String,
location: Object,
}, {
collection: 'test'
});
var Model = mongoose.model('Model', answers);
build and call query
Model.collection.createIndex({ "point": "2dsphere" });
//query = { location : { $near : [ -120.24, 39.21 ], $maxDistance: 0.10 } }
query = {
location: {
$near: {
$geometry: {
coordinates: [-120.24, 39.20 ]
},
$maxDistance: 1000
}
}
}
}
Model.find(query, function ...)
Could you please help me to solve it?..

You can use MONGO SHELL to create indices. Login with the connection string and select your DB and Collection and run
db.collection_name.createIndex({"field_name": "indexing value"})
This should solve the issue.

location.coordinates field must be an array of numbers, in your case it is an array of strings. You should change the fields type to Double.

Related

Mongoose search by array entries ($in) behavior not aligned with MongoDB Atlas

I'm running a Node.js server, connecting to a MongoDB database with mongoose.
Inside my controller, I have several methods that make operations to the database. One of them is this one:
async findMultiple(req, res) {
const [baseSkillsArray] = Array(req.body);
try {
// if there is not baseSkillsArray, skip
if (!baseSkillsArray) {
return res.status(200).send([]);
}
// find all baseSkills using the ids in the baseSkillsArray
const allBaseSkills = await BaseSkill.find({
_id: { $in: [baseSkillsArray.baseSkillArray] } //
});
console.log('test ' + allBaseSkills);
res.status(200).send(allBaseSkills);
} catch (error) {
console.error(error.message);
res.status(500).send('Server error find BaseSkills');
}
}
However, this returns me nothing. I did some debugging and I found the reason is the find id $in the array. So I tried hard coding a value, like '2', for instance.
// find all baseSkills using the ids in the baseSkillsArray
const allBaseSkills = await BaseSkill.find({ _id: { $in: ['2'] } });
No success. So I went to MongoDB Atlas, where my DB is stored. I tried filtering using the same line of code in my collections.
{ _id: { $in: ['2'] } }
Surprisingly, it returns my document as I wanted!
The issue is that I need to make it work with mongoose. Any ideas? Is this a known bug?
There is nothing wrong with the query, nor a bug regarding $in.
In fact, what's wrong is the actual collection name. I manually created a collection in MongoDB Atlas, called "baseSkills". However, mongoose by default transforms your collection name into lowercase and adds an "s" if your collection's name is not in the plural.
So every time I started my server, I noticed that there was a new collection called "baseskills". I assumed it was a bug and deleted it. Only after making this post that I realized the collection was there again.
So I exported the documents to this collection and my query was working fine.
FYI, there is a way to enforce the collection's name in mongoose. When you declare you model, add a second parameter to the Schema function called "collection". Here is an example:
const BaseSkillSchema = new mongoose.Schema({
_id: {
type: String,
required: true
}, ...
}, { collection: 'baseSkills' })
That's it! Sorry for the mess and thank you for your help!
you want to query over mongo db object ids. So you should create a new ObjectId to do that.
import {Types} from 'mongoose';
{ _id: { $in: [new Types.Object("2")] } }
Or if you have 2 ids one generated and one custom created as id then you can query without creating a new object.
{ id: { $in: ['2'] } }

How to get the length of a string field in Mongoose?

I am new to MongoDB and Mongoose.
I am practicing some of the queries with the following Schema and Model:
const articleSchema = mongoose.Schema({
title: String,
content: String,
});
const Article = mongoose.model('article', articleSchema);
Let's say I added the following two documents:
{title: "One", content: "Content One"}
{title: "LongerTitleThanOne", content: "Content Two"}
Which query can I use to find all documents where the "title" length is greater than 3?
I tried the following query but it only works with numbers:
Article.find({title:{$gt:3}}, (err,foundItems)=>{});
Many thanks in advance for your help here.
you can use $strLenCP and $expr:
mongo playground
Article.find({
"$expr": {
"$gt": [
{
"$strLenCP": "$title"
},
3
]
}
})
You can also use aggregation query to achieve the result.
Article.aggregate(
[
{
'$project': {
'titleLength': { '$strLenCP': '$name' }
}
}, {
'$match': {
'titleLength': {
'$gt': 2
}
}
}
])
This is not the best way to do this but it works
I advise you to not use this in production.
First get all your data from you database and store it in a variable then use JavaScript filter function to accomplish your task
For Example
let data = model.find({});
let filter_data = data.filter(data.title.length>8);

Upsert data with a dynamic field name

I just try to do something simple with Mongo but it doesn't work:
I want to upsert datas in an object like: module.xxx.yyy then I tried many things like :
UsersRights.upsert({
condoId: condoId,
userId: manager._id,
}, {
condoId: condoId,
userId: manager._id,
module: {
[defaultRight.xxx] : {
[defaultRight.yyy] : defaultRight.default
}
}
});
but when I want to add a new xxx or a new yyy, it will erase and replace the entire module object and not only add a new key.
I also tried this :
UsersRights.upsert({
condoId: condoId,
userId: manager._id,
}, {
condoId: condoId,
userId: manager._id,
["module." + defaultRight.module + "." + defaultRight.right] : defaultRight.default,
});
but the server show me an error like: MinimongoError: Key module.xxx.yyy must not contain '.'
You need to use the following form:
YourCollection.upsert({
_id: id, (can be other selectors as well)
}, {
$set: setter
});
Setter is an object you create before and should have the following form:
const setter = {};
setter[`${#1Level}.${#2Level}`] = data;
Where #1Level & #2Level are vars naming the fields you want to modify or to add.

How to update user.services for Jasmine testing in Meteor

I am trying to mock out a user for testing out my application, and I have gotten to the point where I can create a test user and log them into the mirror instance of my app.
I need to compare the gmail addresses for peoples accounts, and to test this functionality, I want to add a test email address under user.services.google.email within the Meteor users account database (which is where the accounts-google package stores it, I don't need to mock out an entire user account yet).
What I can't figure out is how to append this information, instead of just overwriting what is already there, this is what my code looks like:
if (Meteor.users.find().count() === 0) {
var testUserDetails = {
email: 'testEmail#gmail.com',
password: 'testPassword'
};
console.log("Creating the Test User");
var newUserId = Accounts.createUser(testUserDetails);
Meteor.users.update({
_id: newUserId
}, {
$set: {
services: {
google: {
email: "testEmail#gmail.com"
}
}
}
});
} else {
console.log("There are already users in the Test database");
}
console.log('***** Finished loading default fixtures *****');
},
And this is what a user looks like:
{
"_id" : "Dw2xQPDwKp58RozC4",
"createdAt" : ISODate("2015-07-30T04:02:03.261Z"),
"services" : {
"password" : {
"bcrypt" : "asdfasdfasdfdsafsadfasdsdsawf"
},
"resume" : {
"loginTokens" : [ ]
}
},
"emails" : [
{
"address" : "testEmail#gmail.com",
"verified" : false
}
]
}
Now $set just rewrites everything within services, and there is no $push operation for mongo or for js, so how should I go about doing this? Should I consume the object and parse it manually?
*Note I have also tried using Meteor's Accounts.onCreateUser(function(options, user) but facing the same issue.
[...] there is no $push operation for mongo [...]
Sure, there is a $push operator, which appends a specified value to an array.
However, I think what you are trying to do is to update a document and keep all values which are already set.
Here is how you can do that:
Query the document first to get the object you want to set.
Update the respective object.
Run the MongoDB update operation to set the new object.
For instance:
var user = Meteor.users.findOne({
_id: newUserId
});
var servicesUserData = user.services;
servicesUserData.google.email = "your_new_email#gmail.com";
Meteor.users.update({
_id: newUserId
}, {
$set: {
"services": {
servicesUserData
}
}
});

mongodb native driver get collection names without database name

How can I get collection names without database name from mongodb native driver for nodeJS?
db.collectionNames(function(err, collections) {
if (err) {
log.error(err);
} else {
log.info(collections);
}
});
This code returns something like this:
databaseName.collection1, databaseName.collection2, databaseName.collection3
But i want to get names: collection1, collection2, collection3
With the MongoDB 2.0.0 driver and higher, you'll need to use listCollections(), as in
db.listCollections().toArray(function(err, collections){
//collections = [{"name": "coll1"}, {"name": "coll2"}]
});
The exact structure of the response is a sub-document with the "name" key in an array:
[
{ name: 'test.cursors' },
{ name: 'test.episodes' },
{ name: 'test.zips' },
{ name: 'test.scripts' }
]
So just use map with a regex replace:
db.collectionNames(function(err, collections) {
console.log(
collections.map(function(x) {
return x.name.replace(/^([^.]*)./,"");
})
);
});
And that will strip out everything up to the first . which is the database prefix. Just in case you actually have collection names with a . in them.

Categories